【温故知新】:`19、删除链表倒数第 n 个结点`快慢指针实现,两种不同的优先处理方式

366 阅读2分钟

题目描述

给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.

当删除了倒数第二个节点后,链表变为 1->2->3->5. 说明:

给定的 n 保证是有效的。

进阶:

你能尝试使用一趟扫描实现吗?

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/re…

解题思路

参考:简洁双指针图解

快慢双指针:

  • 建立快指针p和慢指针q,且记n为初始值即要删除的倒数第n个数。
  • 快指针p先走,同时变量n自减;
  • 当n=0时,此时快指针p已经比慢指针q多走了n步;此后两指针开始同步移动,(ps例如:当n==-1时,q=q.next;p=p.next);
  • 当p指针指向null时,停止遍历,循环体不再继续执行。此时快指针p刚好比慢指针q多走了n+1步;
  • 删除节点即为慢指针的后一个节点q.next;(即:q.next=q.next.next)
  • 特殊情况:需要删除头节点的时候,(即链表有5个节点,删除倒数第5个节点的情况),此时快指针p只比慢指针q多走了n步,慢指针q并未移动,此时n==0,p==null;返回头节点的下一个节点即可;return head.next(q.next);

image.png

题解中:节点类的定义

/***
* Definition for singly-linked list.
* 链表节点定义;
*/
function ListNode(val){
    this.val=val;
    this.next=null;
}

详解:

  • 示例传参为[1,2,3,4,5]和2;
  • @param:head 为指向链表头结点val==1的指针索引;
  • @param:n 为倒数第n个要删除的节点;
  • 特殊情况示例:[1]和1;或者[1,2,3,4,5]和5;此时删除节点即为头结点;

代码

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} n
 * @return {ListNode}
 */
var removeNthFromEnd = function(head, n) {
// 建立快慢指针;
  let p=head,q=head;
  // p指向null为终止条件;
 
  while(p){
      // 慢指针开始移动
      if(n<0){
          q=q.next;
      }
      //快指针先移动n步
      n--;
      p=p.next;
  }//end of while 
   if(n==0){
      return head.next;
  }
  q.next=q.next.next;
  return head;
};

思路2:

  • 建立快指针fast和慢指针slow,且记n为初始值即要删除的倒数第n个数。
  • 快指针先执行n-1步;
    • 如果此时fast.next==null,则,表示此时n==sz;
      • 直接返回head.size
    • 否则,fast=fast.next,此时快指针比慢指针多走n步;
  • 快慢指针同时执行,且终止条件为fast&&fast.next;
    • 即 fast快指针走到最后一个节点停止;
    • 删除节点即为慢指针的后一个节点slow.next;
/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @param {number} n
 * @return {ListNode}
 */
var removeNthFromEnd = function(head, n) {
   // 双指针实现 
   let fast =head,slow=head;
    // 此时只走了n-1步
    while(--n){  
        fast=fast.next;
    }
     //特殊情况优先处理;
    // 如果快指针已经是走链表的最后一个,则返回head.next;提前处理n==sz的情况
    if(!fast.next){
        return head.next;
    }
    // 此时快指针比慢指针多走n步;
    fast=fast.next;
    
    // 快慢指针同时前进
    while(fast&&fast.next){
        fast=fast.next;
        slow=slow.next;
    }
    slow.next=slow.next.next;
    return head;

};