一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第 1 天,点击查看活动详情。
重排链表
来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/re…
题目描述
给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
输入:head = [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)
* }
*/
/**
* @param {ListNode} head
* @return {void} Do not return anything, modify head in-place instead.
*/
var reorderList = function (head) {
if (!head) return null
const nodeArr = []
let cur = head
while (cur) {
nodeArr.push(cur)
cur = cur.next
}
let p = 0,
q = nodeArr.length - 1
let n1, n2
while (p <= q) {
n1 = nodeArr[p++]
n2 = nodeArr[q--]
n1.next = n2
n2.next = nodeArr[p]
}
n2.next = null
}
但是这样需要使用额外的数组,空间复杂度为 O(n)
经过观察我们发现,重排后的链表其实就是原链表的左半边和右半边反转后再合并的结果,即:
1、寻找链表中间节点,将其一分为二
2、将后半部分链表反转
3、交叉合并两个链表
解法二:中间节点 + 反转链表 + 合并链表
/**
* 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 reorderList = function (head) {
// 1. 找到中间节点
// 2. 反转后半部分链表
// 3. 合并两个链表
// 快慢指针寻找中间节点
const midNode = (head) => {
let slow = head
let fast = head
while (fast && fast.next) {
slow = slow.next
fast = fast.next.next
}
return slow
}
// 反转链表
const reverse = (head) => {
let prev = null
let cur = head
while (cur) {
const next = cur.next
cur.next = prev
prev = cur
cur = next
}
return prev
}
// 交叉合并两个链表
const mergeList = (l1, l2) => {
let tmp1, tmp2
while (l1 && l2) {
tmp1 = l1.next
tmp2 = l2.next
l1.next = l2
l1 = tmp1
l2.next = l1
l2 = tmp2
}
}
if (!head) return null
let l1 = head
let l2 = null
const mid = midNode(head)
console.log('mid', mid)
l2 = mid.next
mid.next = null
l2 = reverse(l2)
mergeList(l1, l2)
}
空间复杂度为 O(1)