题目:
给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
核心思路:
方法一: 快慢指针
- 先利用快慢指针,找到
后半段链表,后半段链表需要反转。 无论总共奇数个节点还是偶数个节点,当2n+1超出链表总长时,慢指针所指的位置的下一个节点一定是后半段链表。
// [8] 1 2 3 4 5 6 7 8
// 1 3 5 7
// 1 2 3 4
// mid 4
// 1 2 3 4 & 5 6 7 8
// ====================
// [7] 1 2 3 4 5 6 7
// 1 3 5 7
// 1 2 3 4
// mid 4
// 1 2 3 4 & 5 6 7
2.对后半段链表进行反转
3.对两段链表进行合并,要注意,链表1的长度预定长于链表2,以此为循环条件。
方法二,双指针法:【空间换时间】
- 将链表每个节点断开,放入数组
s - 指针
i从头向尾,指针j从尾向头,重新组装链表
解:
// 方法一:快慢指针
var reorderList = function (head) {
if (!head || !head.next) {
return head;
}
let slow = head;
let fast = head;
while (fast && fast.next && fast.next.next) {
fast = fast.next.next;
slow = slow.next;
}
let mid = slow;
let l1 = head;
let l2 = mid.next; //中间节点后段,无论单双数
mid.next = null;
//反转后半段
let revHead = null;
let p = null;
while (l2) {
p = l2;
l2 = l2.next;
p.next = revHead;
revHead = p
}
const res = {};
p = res;
while (l1) {
//另种可能,一种l1比l2长,另一种一样长
p.next = l1;
l1 = l1.next;
p = p.next;
if (revHead) {
p.next = revHead;
revHead = revHead.next;
p = p.next
}
}
return res.next;
};
方法二:双指针
var reorderList = function(head, s = [], tmp) {// 换行可删除,合并到4行
while (head)
tmp = head.next,
head.next = null,
s.push(head),
head = tmp
var i = -1, j = s.length
while (++i < --j)
s[i].next = s[j],
j !== i + 1 && (s[j].next = s[i + 1])
return s[0]
};