# 快慢指针——删除链表的倒数第 N 个结点
快慢指针指的是两个一前一后的指针,两个指针往同一个方向走,只是一个快一个慢。
在实际做题中可能会出现一前、一中、一后三个指针,这种超过两个的解题方法叫 “多指针法”。
真题描述:给定一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个结点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
没有使用快慢指针的解法:
const list = {
val: 1,
next: {
val: 2,
next: {
val: 3,
next: {
val: 4,
next: {
val: 5,
next: null
}
}
}
}
}
function ListNode(val) {
this.val = val;
this.next = null;
}
var removeNthFromEnd = function (head, n) {
let count = 0;
let dummy = new ListNode();
let cur = head;
dummy.next = head;
while (cur) {
count++;
cur = cur.next;
}
cur = dummy;
let l = count - n;
count = 0;
while (cur && cur.next) {
if (count === l) {
cur.next = cur.next.next;
break;
}
cur = cur.next;
count++;
}
return dummy.next;
};
方法二:
const removeNthFromEnd = function (head, n) {
// 初始化 dummy 结点
const dummy = new ListNode()
// dummy指向头结点
dummy.next = head
// 初始化快慢指针,均指向dummy
let fast = dummy
let slow = dummy
// 快指针闷头走 n 步
while (n !== 0) {
fast = fast.next
n--
}
// 快慢指针一起走
while (fast.next) {
fast = fast.next
slow = slow.next
}
// 慢指针删除自己的后继结点
slow.next = slow.next.next
// 返回头结点
return dummy.next
};
# 链表的反转
真题描述:定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
const reverseList = function(head) {
// 初始化前驱结点为 null
let pre = null;
// 初始化目标结点为头结点
let cur = head;
// 只要目标结点不为 null,遍历就得继续
while (cur !== null) {
// 记录一下 next 结点
let next = cur.next;
// 反转指针
cur.next = pre;
// pre 往前走一步
pre = cur;
// cur往前走一步
cur = next;
}
// 反转结束后,pre 就会变成新链表的头结点
return pre
};
# 局部反转一个链表
真题描述:反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:
1 ≤ m ≤ n ≤ 链表长度。
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
// 入参是头结点、m、n
const reverseBetween = function(head, m, n) {
// 定义pre、cur,用leftHead来承接整个区间的前驱结点
let pre,cur,leftHead
// 别忘了用 dummy 嗷
const dummy = new ListNode()
// dummy后继结点是头结点
dummy.next = head
// p是一个游标,用于遍历,最初指向 dummy
let p = dummy
// p往前走 m-1 步,走到整个区间的前驱结点处
for(let i=0;i<m-1;i++){
p = p.next
}
// 缓存这个前驱结点到 leftHead 里
leftHead = p
// start 是反转区间的第一个结点
let start = leftHead.next
// pre 指向start
pre = start
// cur 指向 start 的下一个结点
cur = pre.next
// 开始重复反转动作
for(let i=m;i<n;i++){
let next = cur.next
cur.next = pre
pre = cur
cur = next
}
// leftHead 的后继结点此时为反转后的区间的第一个结点
leftHead.next = pre
// 将区间内反转后的最后一个结点 next 指向 cur
start.next=cur
// dummy.next 永远指向链表头结点
return dummy.next
};
var reverseBetween = function(head, left, right) {
// 因为头节点有可能发生变化,使用虚拟头节点可以避免复杂的分类讨论
const dummyNode = new ListNode(-1);
dummyNode.next = head;
let pre = dummyNode;
// 第 1 步:从虚拟头节点走 left - 1 步,来到 left 节点的前一个节点
// 建议写在 for 循环里,语义清晰
for (let i = 0; i < left - 1; i++) {
pre = pre.next;
}
// 第 2 步:从 pre 再走 right - left + 1 步,来到 right 节点
let rightNode = pre;
for (let i = 0; i < right - left + 1; i++) {
rightNode = rightNode.next;
}
// 第 3 步:切断出一个子链表(截取链表)
let leftNode = pre.next;
let curr = rightNode.next;
// 注意:切断链接
pre.next = null;
rightNode.next = null;
// 第 4 步:同第 206 题,反转链表的子区间
reverseLinkedList(leftNode);
// 第 5 步:接回到原来的链表中
pre.next = rightNode;
leftNode.next = curr;
return dummyNode.next;
};
const reverseLinkedList = (head) => {
let pre = null;
let cur = head;
while (cur) {
const next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/reverse-linked-list-ii/solution/fan-zhuan-lian-biao-ii-by-leetcode-solut-teyq/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
# 旋转链表
给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。
示例 1:
输入:head = [1,2,3,4,5], k = 2
输出:[4,5,1,2,3]
示例 2:
输入:head = [0,1,2], k = 4
输出:[2,0,1]
提示:
链表中节点的数目在范围 [0, 500] 内
-100 <= Node.val <= 100
0 <= k <= 2 * 109
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/rotate-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
# 两两交换链表中的节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
输入:head = [1,2,3,4]
输出:[2,1,4,3]
示例 2:
输入:head = []
输出:[]
示例 3:
输入:head = [1]
输出:[1]
提示:
链表中节点的数目在范围 [0, 100] 内
0 <= Node.val <= 100
进阶:你能在不修改链表节点值的情况下解决这个问题吗?(也就是说,仅修改节点本身。)
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/swap-nodes-in-pairs
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。