# 重排链表(143)
# 题目
给定一个单链表 L:L0 → L1 → … → Ln-1 → Ln
,
将其重新排列后变为: L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → …
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
# 示例
给定链表 1->2->3->4
, 重新排列为 1->4->2->3
.
给定链表 1->2->3->4->5
, 重新排列为 1->5->2->4->3
.
# 算法
- 使用快慢指针来找到链表中点,并将链表分为两个链表
- 将后半边链表反转
- 将后半边链表依次插入在前半边链表的间隔中
如果链表为偶数个节点,那么前后两个链表的节点数相同;如果链表为奇数个节点,那么后半边链表会比前半边链表多一个节点,所以我们在插入结束后需要判断后半边链表是否还有剩余节点,如果有我们要将其放在最后结果链表的最后面
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
const reorderList = (head) => {
if (!head || !head.next) return head;
// 寻找中点,分隔链表
let fast = head;
let slow = new ListNode();
slow.next = head;
while (fast && fast.next) {
fast = fast.next.next;
slow = slow.next;
}
let mid = slow.next;
slow.next = null;
// 反转后半部分链表
const recursion = (node) => {
if (!node.next) return node;
let reverseHead = recursion(node.next);
node.next.next = node;
node.next = null;
return reverseHead;
};
// 将后半部分插入到前半部分
let frontNode = head;
let reverseNode = recursion(mid);
while (frontNode.next && reverseNode.next) {
const insertedNode = reverseNode;
const insertedNextNode = frontNode.next;
reverseNode = reverseNode.next;
frontNode.next = insertedNode;
insertedNode.next = insertedNextNode;
frontNode = frontNode.next.next;
}
if (reverseNode) frontNode.next = reverseNode;
return head;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
← 分隔链表(86) 两数相加II(445) →