刷题笔记:力扣第19题-删除链表的倒数第N个结点

1.初步思路为两趟扫描,第一趟获取链表节点数cnt,第二趟根据cnt和n找到需要删除的节点,执行删除操作。写出的完整代码如下:

cpp 复制代码
 1. /**
 2.  * Definition for singly-linked list.
 3.  * struct ListNode {
 4.  *     int val;
 5.  *     struct ListNode *next;
 6.  * };
 7.  */
 8. struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
 9.     // 创建虚拟头节点,统一处理删除头节点的边界情况
10.     struct ListNode* dummyHead = (struct ListNode*)malloc(sizeof(struct ListNode));
11.     // 虚拟头节点连接原链表
12.     dummyHead->next = head;
13.     // cur遍历指针,先用来统计链表总节点数量
14.     struct ListNode* cur = dummyHead->next;
15.     // cnt记录链表有效节点总数
16.     int cnt = 0;
17.  
18.     // 第一次遍历,统计链表节点个数
19.     while (cur != NULL){
20.         cur = cur->next;
21.         cnt++;
22.     }
23.  
24.     // 指针重置回虚拟头,准备找到待删除节点的前驱
25.     cur = dummyHead;
26.     // 循环移动 cnt-n 次,定位到倒数第n个节点的前一个节点
27.     for (int i = 0; i < cnt - n; i++){
28.         cur = cur->next;
29.     }
30.  
31.     // 跳过待删除节点,直接连接下下个节点
32.     cur->next = cur->next->next;
33.     // 返回去掉目标节点后的链表头部
34.     return dummyHead->next;
35. }

这其中涉及的知识点:

(1)尽量使用虚拟头结点。

(2)查找的时候只关心链表的真实值,cur指向dummyHead->next。

(3)删除的时候需要找到需要删除节点的前一个节点,cur指向dummyHead。

2.进阶思路限制了只能使用一趟扫描,得知本题可以使用快慢指针,写出的完整代码如下:

cpp 复制代码
 1. /**
 2.  * Definition for singly-linked list.
 3.  * struct ListNode {
 4.  *     int val;
 5.  *     struct ListNode *next;
 6.  * };
 7.  */
 8. struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
 9.     // 创建虚拟头节点,处理需要删除原头节点的边界场景
10.     struct ListNode* dummyHead = (struct ListNode*)malloc(sizeof(struct ListNode));
11.     dummyHead->next = head;
12.     // cur作为快指针,先向前走n步拉开间距
13.     struct ListNode* cur = dummyHead;
14.     for (int i = 0; i < n; i++){
15.         cur = cur->next;
16.     }
17.     // 快指针再多走一步,保证慢指针最终停在待删节点前驱
18.     cur = cur->next;
19.  
20.     // del作为慢指针,初始指向虚拟头
21.     struct ListNode* del = dummyHead;
22.     // 快慢指针同步后移,直到快指针走到链表末尾NULL
23.     while (cur != NULL){
24.         cur = cur->next;
25.         del = del->next;
26.     }
27.  
28.     // 慢指针跳过倒数第n个节点,完成删除
29.     del->next = del->next->next;
30.  
31.     // 返回修改后的链表头节点
32.     return dummyHead->next;
33. }

因为n一定小于链表节点数,所以一定不会越界,于是可以让快指针先走n步,然后慢指针再出发,这样可以保证当快指针走到末尾时与慢指针的距离正好为n。同时又因为删除节点需要找到需要删除节点的上一个节点,所以需要让快指针走完n步后再多走一步。

相关推荐
疯狂打码的少年1 小时前
【数据库技术】复习日:关系代数 + SQL + 规范化(整理对比表)
jvm·数据库·笔记·sql
维克兜率天1 小时前
【维克】特征归一化与标准化:为什么模型对数据的“尺度“很敏感?
人工智能·笔记·python·机器学习·量化
摇滚侠2 小时前
《SpringBoot 3:入门与应用实战》第 12 章 JDBC 与事务 使用 JdbcTemplate 阅读笔记 31
android·spring boot·笔记
金字塔頂の蝸牛2 小时前
商务日语口语全手册(一)
笔记·日语·语言·外语
从零开始的嵌入式之旅3 小时前
day36
linux·c语言·经验分享·笔记·嵌入式硬件
L小航呀4 小时前
代码随想录刷题 Day16
leetcode·面试
墨雨晨曦884 小时前
2026/09/07笔记
笔记
软行4 小时前
LeetCode 每日一题 3876. 构造奇偶一致的数组 II
c++·算法·leetcode
志尊宝4 小时前
Vue3 零基础每日笔记(005):ref 响应式基础——为什么 script 里要 .value
前端·javascript·vue.js·笔记
我不会起名字3225 小时前
一天一道算法题(29):单调栈
java·数据结构·python·算法·leetcode·golang·单调栈