题意描述:
给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
解题思路:
Alice: 这题看起来有点简单啊。
Bob: 之间把每个链表节点的位置存到数组里面,然后双指针从两个方向去读,修改节点之间的指向关系就行了。
Alice: 需要注意的时候,末尾节点的 next 要改成 null
Bob: 这种方法能过的,就是要注意处理一下细节。
Alice: 我看到还有别的方法可以做的,搞得是什么双指针,中间节点,翻转链表合并链表那一套。
Bob: 中间节点 ?中间节点到这里倒是一定会变成末尾节点。如果是偶数个怎么办 ?偶数个没有中间节点的 ?
Alice: 那就是这时候是没有中间节点的,我好像明白了,双指针就是快慢双指针,且速度差是 1,这样一个到末尾的时候,一个刚好到中间。
Bob: 原来是这样,翻转链表和合并链表没啥好讲的了,属于是链表的基本操作了。
Alice: 有个问题,翻转链表的递归写法会爆栈吗 ?
Bob: 应该不会吧,只是修改指向关系而已。
Alice: 我去试试。递归翻转链表的内存使用率有点高啊,只超过了 6% 的人。
Bob: 还能改成循环 ??
Alice: 是啊,翻转链表还能改成循环。我想了好一会呢。
const revertLink = (headNode: ListNode) => {
let prepre = null;
let pre = headNode;
let current = headNode.next
while(current) {
// 翻转
pre.next = prepre;
prepre = pre;
pre = current;
// 继续
current = current.next;
}
pre.next = prepre;
return pre;
}
Bob: o( ̄▽ ̄)d good
代码:
typescript 存储链表节点
function reorderList(head: ListNode | null): void {
const nodeListAddress = [];
let temp = head;
while(temp){
nodeListAddress.push(temp);
temp = temp.next;
}
let left = 0;
let right = nodeListAddress.length - 1;
let pre = null;
while(left < right) {
if(pre) {
pre.next = nodeListAddress[left];
}
nodeListAddress[left].next = nodeListAddress[right];
pre = nodeListAddress[right];
left++;
right--;
}
if(left === right && pre) {
pre.next = nodeListAddress[left];
pre = nodeListAddress[left];
left++;
right--;
}
// 尾节点
if(pre) {
pre.next = null;
}
};
typescript 链表中点 + 翻转链表 + 合并链表
function reorderList(head: ListNode | null): void {
// 边界条件
if(!head.next) {
return;
}
// 快慢指针找到中间节点
const getMiddleNode = (headNode: ListNode) => {
// 从 headNode 开始
let fast = headNode;
let slow = headNode;
let preSlow = null;
while(fast.next){
fast = fast.next;
if(fast.next) {
fast = fast.next
}
preSlow = slow;
slow = slow.next;
}
return preSlow;
}
const revertLink = (headNode: ListNode) => {
// 递归终点
if(headNode.next === null) {
return headNode;
} else {
const ret = revertLink(headNode.next);
headNode.next.next = headNode;
return ret;
}
}
const mergeLink = (left: ListNode, right: ListNode) => {
let current = left;
left = left.next;
while(left || right) {
if(right) {
current.next = right;
current = current.next;
right = right.next;
}
if(left) {
current.next = left;
current = current.next;
left = left.next;
}
}
}
const leftEnd = getMiddleNode(head);
const rightStart = leftEnd.next;
const right = revertLink(rightStart);
// 斩断两个链表之间的联系
leftEnd.next = null;
rightStart.next = null;
mergeLink(head, right);
};
测试用例:
[1000]
参考: