给定一个单链表 L:L0→L1→…→Ln-1→Ln ,
将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→…
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
给定链表 1->2->3->4, 重新排列为 1->4->2->3.
示例 2:
给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.
这道题的思想有两种:
第一种是找到链表中点,把链表中点前的节点放到队列中(先进先出),把中点后的链表节点放到栈中(先进后出),这样每次从队列或者栈中交替取出元素重新构建链表即可。这样的时间复杂度是O(n),空间复杂度是O(n),题目中建议使空间复杂度为O(1),并且第一种方法代码写的比较复杂,要考虑的细节和边界条件比较多(这个后面说)。
第二种在discuss部分看到的思路,我们找到中点节点后对后面的节点进行翻转,然后前面的链表和中点后翻转的链表交替链接形成新链表。这道题不难,主要是作者的思路和一些细节的trick上代码写的比较精巧,思路值得我们借鉴。
/** * 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 || !head->next->next) { return; } ListNode* slow; ListNode* fast; slow = head; fast = head->next; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; } ListNode* pre_head = slow->next; ListNode* tmp = pre_head; //断链接 slow->next = nullptr; ListNode* pre = tmp; ListNode* after = tmp; tmp = tmp->next; pre->next = nullptr; //从slow->next开始反转链表 while (tmp) { after = tmp->next; tmp->next = pre; pre = tmp; tmp = after; } //tmp表示第一个链表头结点,after表示第二个链表头结点 for (tmp = head, after = pre; tmp;) { auto t = tmp->next; tmp->next = after; tmp = tmp->next; after = t; } } };
细节归纳:
1:在用快慢指针找中点的时候,如果快慢指针初始化为fast=head->next且slow=head,且快指针判断的条件为:
while (fast && fast->next)
那么如果是奇数个节点,最后slow指针的位置为第(n+1)/2个节点,刚好是中点,如果是偶数个节点,那么slow指针最后的位置为n/2。
如果快慢指针初始化为fast=head->next且slow=head,且快指针判断的条件为:
while (fast->next && fast->next->next)
那么如果是奇数个节点,最后slow指针的位置为第(n)/2个节点,刚好是中点前一个节点,如果是偶数个节点,那么slow指针最后的位置为n/2。
这里为什么要强调这一点,因为我们是以slow->next作为第二段链表的头结点,所以第二种方法就需要考虑边界情况,把遗漏的中点节点加进去。
2:我们以这点代码为例来讲解如何交替链接两段链表
//tmp表示第一个链表头结点,after表示第二个链表头结点 for (tmp = head, after = pre; tmp;) { auto t = tmp->next; tmp->next = after; tmp = tmp->next; after = t; }常规思想是通过如下条件判断,并通过两个指针分别指向两段链表来遍历。
while(first_head && second_head)但是作者的想法更精巧,思想值得我们借鉴,通过一个中间变量t来不断循环链接两段链表:
第一次循环:提前把tmp的本身的下一个p节点找出,在处理完成后把after赋值给tmp,然后状态变为第二次循环:
第二次循环:
作者便是通过类似“之”子步且通过一个临时变量来实现了两个链表的交替循环构造。
(路线为蓝->红->黑)