Leetcode 19. 删除链表的倒数第N个节点

博客围绕删除链表倒数第n个节点展开,给出两种解法。解法一是两趟扫描,先计算链表长度,再创建虚拟头,找到待删结点前驱进行删除;解法二用快慢指针一趟扫描,先让fast指针走n+1步,再与slow指针同走,fast到尾部时slow指向待删结点前驱,完成删除。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

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

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.

说明:
给定的 n 保证是有效的。

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

解答

解法一:两趟扫描

分为以下几步:

  1. 首先扫描一遍计算链表长度,得到链表长度 len 。
  2. 然后创建一个虚拟头,让删除操作归一化,方便删除。
  3. 找到待删结点的前驱结点,用于删除操作。
  4. 利用前驱结点删除倒数第 n 个节点
代码
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
    	// 首先扫描一遍计算链表长度
        int len = 0;
        ListNode p = head;
        while(p != null) {
            len ++;
            p = p.next;
        }
        
        // 如果 n 越界抛个异常
        if(n < 1 || len < n) throw new RuntimeException("n 越界");
        
        // 添加一个虚拟头,方便删除
        ListNode vHead = new ListNode(0);
        vHead.next = head;
		
		// 找到待删结点的前一个结点,用于删除操作
        ListNode pre = vHead;
        int k = len - n;
        while(k -- > 0) {
            pre = pre.next;
        }
        
        // 删除倒数第 n 个节点
        pre.next = pre.next.next;
           
        return vHead.next;
    }
}
结果

在这里插入图片描述

解法二:快慢指针(一趟扫描)

  1. 首先声明一个虚拟结点,使删除归一化,不受 head 头部结点的干扰。
  2. 使用两枚指针 fast 指针slow 指针,先让 fast 指针走 n + 1 步,再让 slow 指针和 fast 指针一起走。
  3. 在 fast 指针到达尾部时,slow 指针正好指向倒数第 n 个元素的前驱结点
  4. 利用这个待删结点的前驱结点删除倒数第 n 个元素即可。
代码
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        if(n < 1) throw new RuntimeException("n 越界");
        
        // 声明虚拟头节点,使删除过程归一化
        ListNode vHead = new ListNode(0);
        vHead.next = head;
		
		// 声明快慢指针 
        ListNode fast = vHead;
        ListNode slow = vHead;
        
        // 设置快指针的位置
        for(int i = 0; i < n + 1; i ++) {
            if(fast == null) throw new RuntimeException("n 越界");
            fast = fast.next;
        }
        
        // 确定待删除结点的前驱结点
        while(fast != null) {
            fast = fast.next;
            slow = slow.next;
        }
        
        // 删除待删结点
        slow.next = slow.next.next;
        
        return vHead.next;
    }
}
结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值