首页 > 代码库 > [LeetCode]Reorder List

[LeetCode]Reorder List

题目:Reorder List

首尾重新结合形成新的链表;

要求:不能改变链表的元素,空间复杂度O(1)

题目意思:

将链表L0→L1→…→Ln-1→Ln重排变成L0→Ln→L1→Ln-1→L2→Ln-2→…

思路:

首先将链表分为前后两半;L0→L1→...→L(n+1)/2和L(n+1)/2 + 1→…→Ln-1→Ln

然后将后半段的链表逆置;Ln→Ln-1→…→L(n+1)/2 + 1

最后依次遍历两个链表将第二个(后半段)链表对应位置链接到第一个(前半段)的对应为置后面,这样拼接成新的链表。

如何逆置链表?

1.新建新的链表头,指向空指针;

2.从头开始遍历链表,按照如下顺序执行:

  保存当前的下一个位置的节点,

  将当前的下一个位置改为新链表的头部,

  更新新链表的头部,使其指向当前链表,

  更新当前指向的节点,使其指向前面保存的下一个位置;

3.循环执行上面的操作,知道链表为空,然后返回新链表的头指针。

L0→L1→L2→L3→L4→L5→L6→L7

新链表的头部为root = nullptr; p = head;head:L0.

循环的一次操作如下:          第一轮        第二轮    ...

ListNode* q = p->next;//保存下一个节点;q:L1        q:L2
p->next = root;//当前节点插入头部;   p->next:nullptr   p->next:L0
root = p;//更新头结点;         root:L0       root:L1
p = q;//遍历后续节点           p:L1         p:L2

ListNode *LeetCode::reverseList(ListNode* head){
    ListNode* root = nullptr;//逆置后的头结点
    ListNode* p = head;
    while (p){
        ListNode* q = p->next;//保存下一个节点
        p->next = root;//当前节点插入头部
        root = p;//更新头结点
        p = q;//遍历后续节点
    }
    return root;
}

void LeetCode::reorderList(ListNode* head){
    if (!head || !head->next)return;//空链,或单节点
    int count = 0;//记录链长
    ListNode* p = head;
    while (p){//计算链长
        p = p->next;
        ++count;
    }
    if(count % 2)count = (count + 1) / 2;//奇数时,链的后半段的位置
    else count = count / 2;
    p = head;
    for (; count > 0; --count)
    {//找到后半段链的位置
        if (count == 1){//将前半段链尾置空
            ListNode* pre = p;
            p = p->next;
            pre->next = nullptr;
            break;
        }
        p = p->next;
    }
    ListNode* q = p;
    q = reverseList(q);//逆置后半段链表
    p = head;
    while (q){//交替拼接前后半段链表
        ListNode* r = p->next;
        p->next = q;
        q = q->next;
        p->next->next = r;
        p = r;
    }
}

 

[LeetCode]Reorder List