题目介绍
给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例1
输入: head = [1,2,3,4]
输出: [1,4,2,3]
示例2
输入: head = [1,2,3,4,5]
输出: [1,5,2,4,3]
提示:
- 链表的长度范围为
[1, 5 * 10^4] 1 <= node.val <= 1000leetcode-143 重排链表
b站视频
解题思路
思路一
由于链表没有下标,我们不方便对链表的节点进行操作,因此先将所有的节点保存到数组中,通过数组下标来将链表重排
- 先将链表的节点全部存到数组中
- 定义两个指针 i、j 分别从数组的前后开始遍历
- 将 j 指向的节点插入到 i 节点和其下一个节点之间
- i + 1, j - 1
- 重复 3-4,直到 i >= j
解题代码
var reorderList = function(head) {
const arr = []
let p = head
// 为了使用节点的下标,将节点都保存到数组中
while (p) {
arr.push(p)
p = p.next
}
let i = 0; j = arr.length - 1
while (i < j) {
arr[i].next = arr[j]
i++
// 当 i === j 时,说明 j 是 i 的下一位,不需要再进行交换
if (i === j) {
break
}
arr[j].next = arr[i]
j--
}
// 需要将尾节点的 next 指向 null,否则会形成环形链表
arr[i].next = null
return arr[0]
};
思路二:链表翻转
可以将链表的后半段进行翻转,然后将翻转之后的新链表从头节点开始依次插入到原链表中
- 定义一个链表翻转的方法
- 定义快慢指针
p、q分别指向头节点和头节点的下一个节点 - 每次
p指针走一步,q指针走两步 - 当
q指针指向空或者q指针的下一个节点为空时,此时p节点指向待翻转链表的前一个节点 - 将
p指针之后的链表进行翻转,p指针的下一个节点指向空 - 将翻转后的链表从头节点开始依次间隔插入到原链表中
- 返回原链表的头节点
解题代码
var reorderList = function(head) {
// 如果链表为空或者只有一个节点,不需要重排
if (!head || !head.next) return head
// 定义快慢指针
let p = head, q = head.next
// 当 q 走到 null 或者链表最后一个节点时,p 走到链表中点
while (q && q.next) {
p = p.next
q = q.next.next
}
// 将链表的后半段翻转
const newList = reverse(p.next)
p.next = null
p = head
q = newList
// 将两个链表拼接成一个
while (q) {
const q_next = q.next
q.next = p.next
p.next = q
p = p.next.next
q = q_next
}
return head
};
// 翻转链表
var reverse = function (head) {
let p = head, next = p.next
while (head.next) {
head.next = head.next.next
next.next = p
p = next
next = head.next
}
return p
}