快慢指针——删除链表的倒数第 N 个结点
真题描述:给定一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
示例: 给定一个链表: 1->2->3->4->5, 和 n = 2. 当删除了倒数第二个结点后,链表变为 1->2->3->5. 说明: 给定的 n 保证是有效的。
链表删除问题中,若走两次遍历,我们做了两件事:
1.求长度
2.做减法,找定位。
若用快慢指针,我们其实是把做减法和找定位这个过程给融合了。通过快指针先行一步、接着快慢指针一起前进这个操作,巧妙地把两个指针之间的差值保持在了“n”上(用空间换时间,本质上其实就是对关键信息进行提前记忆,这里咱们相当于用两个指针对差值实现了记忆),这样当快指针走到链表末尾(第 len 个)时,慢指针刚好就在 len - n 这个地方稳稳落地。
/*** @param {ListNode} head* @param {number} n* @return {ListNode}*/const removeNthFromEnd = function(head, n) {// 初始化 dummy 结点const dummy = new ListNode()// dummy指向头结点dummy.next = head// 初始化快慢指针,均指向dummylet fast = dummylet slow = dummy// 快指针闷头走 n 步while(n!==0){fast = fast.nextn--}// 快慢指针一起走while(fast.next){fast = fast.nextslow = 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 = function(head) {// 初始化前驱结点为 nulllet 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
/*** @param {ListNode} head* @param {number} m* @param {number} n* @return {ListNode}*/// 入参是头结点、m、nconst reverseBetween = function(head, m, n) {// 定义pre、cur,用leftHead来承接整个区间的前驱结点let pre,cur,leftHead// 别忘了用 dummy 嗷const dummy = new ListNode()// dummy后继结点是头结点dummy.next = head// p是一个游标,用于遍历,最初指向 dummylet 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 指向startpre = start// cur 指向 start 的下一个结点cur = pre.next// 开始重复反转动作for(let i=m;i<n;i++){let next = cur.nextcur.next = prepre = curcur = next}// leftHead 的后继结点此时为反转后的区间的第一个结点leftHead.next = pre// 将区间内反转后的最后一个结点 next 指向 curstart.next=cur// dummy.next 永远指向链表头结点return dummy.next};
