143. Reorder List

题目描述:给链表如L: L0→L1→…→Ln-1→Ln,将其重新排序为L0→Ln→L1→Ln-1→L2→Ln-2→…,要求空间复杂度为O(1),且不修改结点的值。

分析:若没有要求,可以先遍历链表在数组中记录每个结点的值,然后修改链表即可。纯链表操作就要在指针上做处理了,先找到中间结点断开,将后半截链表转置后与前半段merge。时间复杂度O(n),空间O(1)。

代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    void reorderList(ListNode* head) {
        if (!head || !head -> next) return ;
        
        ListNode *slow = head, *fast = head, *pre = 0;                
        //设快慢指针用于找到链表中间结点,slow指针每次走一步,fast走两步,fast到链表尾结点时slow就在中间结点
        while (fast && fast -> next)      //由于fast一次走两步,故既可能直接跳过尾结点,也可能最后正好到尾结点,即链表结点个数奇偶的问题
        {
            pre = slow;
            slow = slow -> next;
            fast = fast -> next -> next;
        }
        pre -> next = nullptr;              //pre是前半段的最后一个结点
        slow = reverse(slow);            //将后半段转置
        //merge两链表
        ListNode * cur = head;
        while (cur -> next)
        {
            ListNode *tmp = cur -> next;
            cur -> next = slow;
            slow = slow -> next;
            cur -> next -> next = tmp;
            cur = tmp;
        }
        cur -> next = slow;
    }
    
    //转置两链表不是用的头插法,而是直接设三个指针指向连续的三个结点,在从前向后遍历的过程中修改当前cur所指结点的指针,指向其原前结点。
    ListNode* reverse(ListNode *head)
    {
        if (!head || !head -> next) return head;
        ListNode *pre = head;
        for (ListNode *cur = head -> next, *nx = cur -> next;
             cur;
             pre = cur, cur = nx, nx = nx ? nx -> next : nullptr)
            cur -> next = pre;
        head -> next = nullptr;
        return pre;
    }
};

你可能感兴趣的:(143. Reorder List)