给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
你应当 保留 两个分区中每个节点的初始相对位置。
链接:
143. 重排链表 - 力扣(LeetCode) (leetcode-cn.com)
利用数组可以直接按顺序访问指定元素,重建该链表即可
/**
* @param {ListNode} head
* @return {void} Do not return anything, modify head in-place instead.
*/
var reorderList = function(head) {
if (head === null || head.next === null) {
return head;
}
var list = [], curr = head;
while(curr !== null) {
list.push(curr);
curr = curr.next;
}
var i = 0, j = list.length - 1;
while (i < j) {
list[i].next = list[j];
i++;
if (i == j) {
break;
}
list[j].next = list[i];
j--;
}
list[i].next = null;
};
时间复杂度: O(n)
空间复杂度: O(n)
目标链表即为将原链表的左半端和反转后的右半端合并后的结果
可划分为三步:
将原链表的右半段反转(参考「206. 反转链表」)
合并左右两段链表
var reorderList = function (head) {
if (head === null || head.next === null) {
return head;
}
// 1. 找中点,使用 fast,slow 快慢双指针法,奇数个节点找到中点,偶数个节点找到中心左边的节点
var slow = head,
fast = head.next;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
// 2. 断开中点,反转后半部分
var head2 = null,
next = slow.next;
slow.next = null;
slow = next;
while (slow != null) {
next = slow.next;
slow.next = head2;
head2 = slow;
slow = next;
}
// 3. 合并链表head和head2
var curr = head;
var curr2 = head2;
while (curr != null && curr2 != null) {
next = curr.next;
curr.next = curr2;
curr2 = curr2.next;
curr.next.next = next;
curr = next;
}
};
时间复杂度: O(n)
空间复杂度: O(1)
上面代码也可以按功能分出以下代码:
/**
* @param {ListNode} head
* @return {void} Do not return anything, modify head in-place instead.
*/
var reorderList = function (head) {
if (head === null || head.next === null) {
return head;
}
var mid = middleNode(head);
var l1 = head;
var l2 = mid.next;
mid.next = null;
l2 = reverseList(l2);
mergeList(l1, l2);
};
// 合并
var mergeList = function (list1, list2) {
var tmp1, tmp2;
while (list1 != null && list2 != null) {
tmp1 = list1.next;
tmp2 = list2.next;
list1.next = list2;
list1 = tmp1;
list2.next = list1;
list2 = tmp2;
}
};
// 反转链表
var reverseList = function (head) {
var prev = null,
curr = head,
next = null;
while (curr != null) {
next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
};
// 获取中间节点, 奇数个节点找到中点,偶数个节点找到中心左边的节点
var middleNode = function (head) {
if (head === null) {
return null;
}
let slow = head,
fast = head.next;
while (fast !== null && fast.next !== null) {
fast = fast.next.next;
slow = slow.next;
}
return slow;
};