Given a singly linked list L: L0→L1→…→Ln-1→Ln,
reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…
You may not modify the values in the list’s nodes, only nodes itself may be changed.
Example 1:
Given 1->2->3->4, reorder it to 1->4->2->3.
Example 2:
Given 1->2->3->4->5, reorder it to 1->5->2->4->3.
调换链表的顺序,第i个连接第n-i个
因为是单向链表,所以不知道最后一个,每次调换后都再遍历一次链表找到最后一个元素,运行结果只超过5%
思路:
找到中间的点,把链表分成前后两段,然后后半段倒序排列,这样就可以移动前半段和后半段的指针,进行顺序交换。
问题转化成链表的倒序排列,这时候先小圈调顺序,再大圈
比如3->4->5->6
先调3,4 : 4->3->5->6
再大圈,把5移到前面:5->4->3->6
再把6移到前面:6->5->4->3
所以这个题先把链表分两段:
分段方法就是一个faster指针,一个slower指针,faster一次走2步,slower一次走1步,这样faster走到最后一个元素的时候,slower正好就走到中间的元素
ListNode p1 = head;
ListNode p2 = head;
//get the middle point..
while (p2.next != null && p2.next.next != null) {
p1 = p1.next;
p2 = p2.next.next;
}
然后是后半段链表倒序排列
按照从小圈到大圈的顺序
因为上面的p1是中间位置,所以利用p1
**出错点:
注意while中的顺序,刚开始写成了preMiddle.next = current, current.next = preMiddle.next
这时候相当于current.next = current, 然后就死循环掉了。。
ListNode preMiddle = p1;
ListNode preCurrent = preMiddle.next;
ListNode current = preCurrent.next;
//right half revert..
while (current != null) {
preCurrent.next = current.next;
current.next = preMiddle.next;
preMiddle.next = current;
current = preCurrent.next;
}
最后利用前半段和后半段的指针连接达到目的
p1 = head;
p2 = preMiddle.next;
while (p1 != preMiddle) {
preMiddle.next = p2.next;
p2.next = p1.next;
p1.next = p2;
p1 = p2.next;
p2 = preMiddle.next;
}
完整代码:
public void reorderList(ListNode head) {
if (head == null || head.next == null || head.next.next == null) {
return;
}
ListNode p1 = head;
ListNode p2 = head;
//get the middle point..
while (p2.next != null && p2.next.next != null) {
p1 = p1.next;
p2 = p2.next.next;
}
ListNode preMiddle = p1;
ListNode preCurrent = preMiddle.next;
ListNode current = preCurrent.next;
//right half revert..
while (current != null) {
preCurrent.next = current.next;
current.next = preMiddle.next;
preMiddle.next = current;
current = preCurrent.next;
}
p1 = head;
p2 = preMiddle.next;
while (p1 != preMiddle) {
preMiddle.next = p2.next;
p2.next = p1.next;
p1.next = p2;
p1 = p2.next;
p2 = preMiddle.next;
}
}