快慢指针——删除链表的倒数第 N 个结点
给定一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个结点后,链表变为 1->2->3->5.
说明: 给定的 n 保证是有效的。
题解:
/**
* @param {ListNode} head
* @param {number} n
* @return {ListNode}
*/
const removeNthFromEnd = (head, n) => {
//初始化头节点
const dummy = new ListNode();
dummy.next = head;
//快慢指针
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
题解:
/**
* @param {ListNode} head
* @return {ListNode}
*/
const reverseList = (head) => {
//初始化节点为null作为反转的尾节点
let pre = null;
//初始化头节点
let cur = head;
while(cur !== null){
// 记录下一个节点
let next = cur.next;
// cur和next断开 cur反转
cur.next = pre;
//指针往前走
pre = cur;
cur = next;
}
return pre;
}
规则:
处理链表结点之间的指针关系,pre的结果为已反转的链表,cur与next节点断开,存储旧指针用于遍历
局部反转一个链表
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
示例:
说明: 1 ≤ m ≤ n ≤ 链表长度。
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
题解:
/**
* @param {ListNode} head
* @param {number} m
* @param {number} n
* @return {ListNode}
*/
const reverseBetween = (head, m, n) => {
let pre, cur, leftHead;
const dummy = new ListNode();
dummy.next = head;
// 保存反转区间m-1的前驱节点
let p = dummy;
for(let i = 0; i < m - 1; i++){
p = p.next;
}
leftHead = p;
// 反转区间
let start = leftHead.next;
pre = start;
cur = pre.next;
for(let i = m; i < n; i++){
let next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
// 连接反转后的第一个节点
leftHead.next = pre;
start.next = cur;
//返回头指针
return dummy.next;
}
规则:
利用指针进行缓存