手摸手提桶跑路——LeetCode19. 删除链表的倒数第 N 个结点

91 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第33天,点击查看活动详情

题目描述

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

示例 1:

捕获.PNG

输入: head = [1,2,3,4,5], n = 2
输出: [1,2,3,5]

示例 2:

输入: head = [1], n = 1
输出: []

示例 3:

输入: head = [1,2], n = 1
输出: [1]

提示:

  • 链表中结点的数目为 sz
  • 1 <= sz <= 30
  • 0 <= Node.val <= 100
  • 1 <= n <= sz

解题思路——遍历

根据题目可以知道找的是倒数第 n 个节点,这个 n 一定比节点数量小。

那么我们简单的,像排队点人头一样,如果正常我们想要找到倒数第 n 个人,直接从最后一个开始数就完事了,但是单链表只能从头开始遍历,而且不能从后一个节点找到前一个节点,所以如果我们想找到倒数第 n 个人的话,我们首先要知道链表的总节点数 size,然后从头开始数,数到 size-n 个时,这个人就是倒数第 n 个人了。

题解

var removeNthFromEnd = function(head, n) {
    let cnt = 0, temp = head;
    while(temp) {
        cnt++;
        temp=temp.next;
    }
    
    if(n % cnt === 0) {
        return head.next || null;
    }

    cnt = cnt - n;

    temp = head;
    while(--cnt) {
        temp=temp.next;
    }
    temp.next = (temp.next && temp.next.next) || null;
    return head;
};

捕获.PNG

解题思路——双指针

单链表的解法一般是双指针,也称作快慢指针。

双指针一般是以不同速度移动,一个指针跑的快一些,另一个指针跑的慢一些;还有种是一个指针先跑,另一个指针在某个条件触发时才进行移动。

那么这道题就可以用双指针解了。题目要求我们删除的是倒数第 n 个节点,我们可以定义一个快指针,抢跑于慢指针 n 步的距离,随后两个指针以 相同的速度 跑,这样一来,当快指针跑到终点的时候,慢指针差了快指针 n 步,此时的慢指针所在的位置就相当于倒数第 n 个节点了。

删除链表的倒数第n个节点.gif

题解

/**
 * 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 slow = head, fast = head.next;
    while(--n) {
        fast = fast.next;
    }
    if(!fast){
        return head.next;    
    }
    while(fast.next) {
        fast = fast.next;
        slow = slow.next;
    }
    slow.next = slow.next.next;
    return head;
};

捕获.PNG