Given a singly linked list L: L0→L1→…→Ln-1→Ln,
reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…html
You may not modify the values in the list's nodes, only nodes itself may be changed.node
Example 1:post
Given 1->2->3->4, reorder it to 1->4->2->3.
Example 2:url
Given 1->2->3->4->5, reorder it to 1->5->2->4->3.
这道链表重排序问题能够拆分为如下三个小问题:spa
1. 使用快慢指针来找到链表的中点,并将链表从中点处断开,造成两个独立的链表。指针
2. 将第二个链翻转。code
3. 将第二个链表的元素间隔地插入第一个链表中。htm
解法一:blog
class Solution { public: void reorderList(ListNode *head) { if (!head || !head->next || !head->next->next) return; ListNode *fast = head, *slow = head; while (fast->next && fast->next->next) { slow = slow->next; fast = fast->next->next; } ListNode *mid = slow->next; slow->next = NULL; ListNode *last = mid, *pre = NULL; while (last) { ListNode *next = last->next; last->next = pre; pre = last; last = next; } while (head && pre) { ListNode *next = head->next; head->next = pre; pre = pre->next; head->next->next = next; head = next; } } };
咱们尝试着看可否写法上简洁一些,上面的第二步是将后半段链表翻转,那么咱们其实能够借助栈的后进先出的特性来作,若是咱们按顺序将全部的结点压入栈,那么出栈的时候就能够倒序了,实际上就至关于翻转了链表。因为只需将后半段链表翻转,那么咱们就要控制出栈结点的个数,还好栈能够直接获得结点的个数,咱们减1除以2,就是要出栈结点的个数了。而后咱们要作的就是将每次出栈的结点隔一个插入到正确的位置,从而知足题目中要求的顺序,链表插入结点的操做就比较常见了,这里就很少解释了,最后记得断开栈顶元素后面的结点,好比对于 1->2->3->4,栈顶只需出一个结点4,而后加入原链表以后为 1->4->2->3->(4),由于在原链表中结点3以后是连着结点4的,虽然咱们将结点4取出插入到结点1和2之间,可是结点3后面的指针仍是连着结点4的,因此咱们要断开这个链接,这样才不会出现环,因为此时结点3在栈顶,因此咱们直接断开栈顶结点便可,参见代码以下:排序
解法二:
class Solution { public: void reorderList(ListNode *head) { if (!head || !head->next || !head->next->next) return; stack<ListNode*> st; ListNode *cur = head; while (cur) { st.push(cur); cur = cur->next; } int cnt = ((int)st.size() - 1) / 2; cur = head; while (cnt-- > 0) { auto t = st.top(); st.pop(); ListNode *next = cur->next; cur->next = t; t->next = next; cur = next; } st.top()->next = NULL; } };
参考资料:
https://leetcode.com/problems/reorder-list/
https://leetcode.com/problems/reorder-list/discuss/45175/Java-solution-with-stack
https://leetcode.com/problems/reorder-list/discuss/44992/Java-solution-with-3-steps