[路飞]_删除链表的倒数第 N 个结点

330 阅读3分钟

「这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战

leetcode-19 删除链表的倒数第 N 个结点

题目介绍

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

示例1

image.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 步就可以走到待删除节点的上一个节点,然后将该节点的 next 指针指向待删除节点的下一个节点就可以删除链表的倒数第 N 个结点了

解题步骤

  1. 定义一个虚拟头节点 newNode(防止要删除的节点是链表的头节点),将虚拟头节点的 next 指向真实的头节点
  2. 定义 p 指针从虚拟头节点开始遍历,k 用于记录链表的长度
  3. 如果 p.next 不为空,将 p 指向 p.next,然后 k++
  4. 在第 3 步记录完链表长度之后,将 p 指针重新指向链表的虚拟头节点 newNode,然后 p 指针往前走 k - n 步,到达待删除节点的上一个节点
  5. p 指针指向节点的 next 指针指向 p.next.next,即可删除待删除的节点
  6. 返回虚拟头节点的下一个节点

删除链表的倒数第 N 个结点.gif

解题代码

var removeNthFromEnd = function(head, n) {
    // 定义一个虚拟头节点
    const newNode = new ListNode(-1, head)
    // 定义一个指针指向虚拟头节点
    let p = newNode, k = 0
    // 获取链表的长度
    while (p.next) {
        p = p.next
        k++ 
    }
    // p指针指向虚拟头节点
    p = newNode
    // 从p节点走到删除节点前一个节点的距离
    let step = k - n
    // 走到删除节点的前一个节点
    while (step--) {
        p = p.next
    }
    // 删除倒数第n个节点
    p.next = p.next.next
    // 返回头节点
    return newNode.next
};

思路二:双指针法

可以利用两个指针,第一个指针比第二个指针先走 n 步,然后两个指针同时往前走,当快指针走到链表尾部时,慢指针指向的节点即为待删除节点的上一个节点

解题步骤

  1. 定义一个虚拟头节点 newNode(防止要删除的节点是链表的头节点),将虚拟头节点的 next 指向真实的头节点
  2. 定义快指针 next 和慢指针 pre 同时从虚拟头节点开始
  3. 快指针 next 先往前走 n
  4. 快慢指针同时往前走,直到快指针 next 走到链表尾部
  5. pre 指向的节点的 next 指针指向 pre.next.next
  6. 返回虚拟头节点的下一个节点

删除链表的倒数第 N 个结点(1).gif

解题代码

var removeNthFromEnd = function(head, n) {
    // 创建虚拟头节点
    const newNode = new ListNode(-1, head)
    // 定义两个指针指向虚拟头节点
    let pre = next = newNode
    // 快指针往前走n个位置
    while (n--) {
        next = next.next
    }
    // 快指针和慢指针同时移动,当快指针走到结尾时,慢指针指向删除节点的前一个节点
    while (next.next) {
        pre = pre.next
        next = next.next
    }
    // 将慢指针的下一个节点指向删除节点的下一个节点
    pre.next = pre.next.next
    // 返回头节点
    return newNode.next
};

至此,我们用两种方法删除了链表的倒数第 N 个结点