问题描述
- Given a singly linked list L:
L0→L1→…→Ln-1→Ln
,
reorder it to:L0→Ln→L1→Ln-1→L2→Ln-2→…
You must do this in-place without altering the nodes’ values.
For example,
Given{1,2,3,4},
reorder it to{1,4,2,3}
. - 地址
问题分析
分为三步:
- 找到中间节点(实际上是前部分链表的末尾节点),可以将链表“一分为二”
- 如何 one pass找到中间节点呢? 快慢双指针
建议是利用快慢指针找到前半部分链表的末尾节点,因为利用链尾节点,可以很方便找后半部分的链头。例如对于1 -> 2 -> 3 -> 4
而言,slow
最终定位到 2,而对于1 -> 2 -> 3 -> 4 -> 5
而言,slow
最终定位到 3,所以这种一分为二的方法,前半部分比后半部分等长或者大于1。
- 如何 one pass找到中间节点呢? 快慢双指针
将后半部分链表反转
- 利用头插法。类似于LeetCode 92. Reverse Linked List II 中的方法。
- 具体如下,每次将 4后面的节点连在 3的后面,然后4取代后面节点的位置,此循环,直至4到末尾。因为反转链表前一定有节点(3),所以无需 dummy 节点
1 -> 2 -> 3 -> 4 -> 5 -> 6
1 -> 2 -> 3 -> 5 -> 4 -> 6
1 -> 2 -> 3 -> 6 -> 5 -> 4
将前后链表合并
- 方法1: 将两部分链表分开,然后一一合并,最终连上前部分多的那部分
- 方法2: 直接原地调整,具体见代码
- 找到中间节点(实际上是前部分链表的末尾节点),可以将链表“一分为二”
经验教训
- 如何one pass 找到链表的中间节点?
- 最好slow定位到前部分末尾节点
//利用快慢指针,最终时slow指向前一半链表的末尾
ListNode slow = head;
ListNode fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
- 如何反转部分链表?
- 类似头插法
- 如何合并两链表
- 注意 tail 的变化
代码实现
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public void reorderList(ListNode head) {
if (head == null || head.next == null || head.next.next == null ) {
return;
}
//利用快慢指针,最终时slow指向前一半链表的末尾
ListNode slow = head;
ListNode fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
//利用头插法,将后一半链表进行反转
ListNode preList = slow;
ListNode curNode = slow.next;
while (curNode.next != null) {
ListNode insertNode = curNode.next;
curNode.next = insertNode.next;
insertNode.next = preList.next;
preList.next = insertNode;
}
//将前部分和后部分左右相间连在一起(不分开)
//这种相连方法只适用于两链等长或者前者比后者大1
ListNode part1 = head;
ListNode part2 = preList.next;
while (part1 != preList) {
preList.next = part2.next;
part2.next = part1.next;
part1.next = part2;
part1 = part2.next;
part2 = preList.next;
}
//以下是前后部分先分成两条链表,再连
/*
preList.next = null;
ListNode dummy = new ListNode(0);
ListNode tail = dummy;
while (part1 != null && part2 != null) {
tail.next = part1;
//注意此刻便更新!!!
part1 = part1.next;
tail.next.next = part2;
part2 = part2.next;
tail = tail.next.next;
}
//因为前部分长度有可能比后部分大1(整体长度为奇数),所以再把它跟在后面
tail.next = part1;
*/
}
}