正题
重排链表
给定一个单链表 L **的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
解析:
仔细分析一下,该题是要将链表重新排列,规则是将原链表的倒序,间隔插入到正序中。
再详细的文字解释不如一张图来说明如何操作:
原理:
-
找到链表的中间节点,得到新的链表 middle (middle 是 原链表的一部分)
-
将 middle 链表反转
-
将 middle 间隔插入原链表
-
删除 原链表后面的所有节点
寻找链表中间节点
之前有提到过如何寻找链表的中间节点,我们经常用到的方法就是快慢指针法,设 快指针 p 和 慢指针 middle, p 每次前进2格, middle 每次前进一格,当 p 遍历完毕时,middle 所指的节点即为原链表的中间节点。
let p = head
let middle = p
while(p && p.next && p.next.next) {
p = p.next.next
middle = middle.next
}
反转 Middle 链表
具体算法可以参考之前的文章 一张图说明链表反转
var transList = function (head) {
let cur = head
let pre = null
while (cur) {
const next = cur.next
cur.next = pre
pre = cur
cur = next
}
return pre
}
middle = transList(middle.next)
穿插链表
需要注意 p 节点 和 m 节点是带有指针的,所以要预先缓存 p.next 和 m.next
let m = middle
while(m) {
const pNext = p.next
const mNext = m.next
p.next = m
p.next.next = pNext
p = pNext
m = mNext
}
删除多余部分
p.next = null
show code
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {void} Do not return anything, modify head in-place instead.
*/
var transList = function (head) {
let cur = head
let pre = null
while (cur) {
const next = cur.next
cur.next = pre
pre = cur
cur = next
}
return pre
}
var reorderList = function(head) {
let p = head
let middle = p
while(p && p.next && p.next.next) {
p = p.next.next
middle = middle.next
}
middle = transList(middle.next)
p = head
let m = middle
while(m) {
const pNext = p.next
const mNext = m.next
p.next = m
p.next.next = pNext
p = pNext
m = mNext
}
p.next = null
};
思路不难,难点在于每一步操作都需要有经验的积累,如果你不知道或者对找链表某个节点以及链表的反转不够敏感,这题将会有很多的阻碍困住你,如果你足够了解,把他们灵活运用就不难了。