每日刷题第17天 2021.1.12
重排链表
- 难度:中等
- 方法:链表
题目
- 给定一个单链表 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 * 104] 1 <= node.val <= 1000
解法
- 快慢指针 slow fast,寻找中点
- 可以采取建立两个指针,一个指针一次遍历两个节点,另一个节点一次遍历一个节点,当快指针遍历到空节点时,慢指针指向的位置为链表的中间位置,这里解决问题的算法称为「快慢指针」
- 找到中点之后,将后半部分的链表进行翻转
- 前后链表,进行连接即可
/**
* 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) {
// 解法: 先快慢指针,再反转后半段链表,之后将两个链表进行合并
// 快慢指针找到中点
let slow = head;
let fast = head;
// 记录中点的前一个节点
let pre = null;
// 记录链表的长度
let len = 1;
while (null != fast.next) {
if (fast.next.next != null) {
// 快指针跳2
fast = fast.next.next;
len += 2;
}else {
fast = fast.next;
len++;
}
// 慢指针跳1
pre = slow;
slow = slow.next;
}
// 循环结束后,fast指针为尾节点,slow指针为中间节点
if (len == 1) {
return head;
}
// 获取前半段链表
pre.next = null;
// slow指针记录了后半段的链表,现在将其进行反转reverse,使用三个指针
function reverse(slow) {
let prev = null;
let cur = slow;
let next = null;
while (cur) {
next = cur.next;
cur.next = prev;
prev = cur;
cur = next;
}
return prev;
}
slow = reverse(slow);
// 将两个链表进行合并
let ans = new ListNode();
ans.val = 111;
let ansH = ans;
while (head || slow) {
if (head) {
ans.next = head;
head = head.next;
ans = ans.next;
}
if (slow) {
ans.next = slow;
slow = slow.next;
ans = ans.next;
}
}
return ansH.next;
};
附录
- 快慢指针:寻找链表的中点。
- 原理:fast和slow指针,让fast移动的位置是slow移动的两倍,这样当fast指到链表末尾时,slow刚好指到链表的中点。
- 翻转链表:三指针prev、cur、next
- 合并链表:⚠️一定要记住生成的链表头