LeetCode19、删除链表的倒数第 N 个结点

65 阅读1分钟

LeetCode 系列记录我学习算法的过程。

持续创作,加速成长!这是我参与「掘金日新计划 6 月更文挑战」的第 18 天,点击查看活动详情

题目

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

示例:

image.png

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

提示

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

思路

这题解起来倒是不难,用两个循环来实现,第一个循环获取结点数,第二个循环删除指定位置结点

  • 定义 temp 暂存 head,遍历 head 获取结点数 len
  • 如果是删除头结点,即 len === n,返回 head.next 即可
  • temp 重置为 head 再次进行遍历
  • 遍历到要删除的位置的前一个结点,即 len - n 位置时,将下一个结点修改为下下个结点即可实现删除下个节点
  • 跳出循环,返回 head

代码实现

/**
 * 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 len = 0, // 记录链表的结点数
        idx = 0, // 标记当前结点下标
        temp = head
    // 遍历链表 记录结点数
    while(temp) {
        len++
        temp = temp.next
    }
    // 如果结点数和 n 一致,即删除第一个结点,直接返回第二个结点即可
    if (len === n) return head.next
    // 重置temp
    temp = head 
    while(temp) {
        idx++
        // 删除倒数第 n 个结点,即删除第 len - n + 1 个结点
        // 所以在其前一个(即 len - n)结点将其下一个结点改变为下下个结点
        // 即可实现删除下一个结点
        if (idx === (len - n)) {
            temp.next = temp.next?.next || null
            break
        }
        temp = temp.next
    }
    return head
};

优化

题目其实还给了个进阶目标,即 你能尝试使用一趟扫描实现吗?

但是我没有想到如何来实现,所以就去学习了下别人的题解

通过快慢指针的方式,要删除倒数第 n 项,只需要让快指针和慢指针间隔 n

当快指针指到 null 时,慢指针下一项就是需要删除的项

/**
 * 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 = null, // 慢指针置空
        fast = head, // 快指针指向头结点
        idx = 1 // 快指针下标
    // 当快指针指向 null 时 结束循环
    while(fast) {
        // 当快指针下标大于 n 时,开始移动慢指针
        if(idx > n) {
            // 慢指针此时与快指针相差 n 项
            slow = slow ? slow.next : head
        }
        // 移动快指针和下标
        fast = fast.next
        idx++
    }
    // 如果慢指针为 null,即删除头结点
    if (!slow) return head.next
    // 慢指针不为 null,则删除下一结点
    slow.next = slow.next?.next || null
    return head
};

image.png