首页 > 其他分享 >LeetCode | 19. 删除链表的倒数第 N 个结点

LeetCode | 19. 删除链表的倒数第 N 个结点

时间:2023-10-23 21:23:24浏览次数:40  
标签:00 19 倒数第 链表 fa del next 节点 beforedel

1 相关标签

链表、双指针、C 语言

2 报错情况

2.1 题目

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

2.2 错误代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
    int distance = 0;   // 计数器
    struct ListNode *end = head, *del = head, *beforedel = head;

    // 定位删除的节点
    while(end){
        if(distance < n){
            ++distance;
        }
        else{
            beforedel = del;    // 定位删除节点前的节点
            del = del->next;
        }
        end = end->next;
    }

    // 删除节点
    beforedel->next = beforedel->next->next;
    free(del);

    return head;    
}

2.3 测试用例

[1]
1

2.4 报错内容

runtime error: member access within null pointer of type 'struct ListNode' [solution.c]

在struct ListNode类型的空指针中访问成员

3 Debug思路

3.1 排查出错原因

运行原有示例中的其他两组

[1,2,3,4,5]
2
[1,2]
1

均输出正确结果。

[1,2,3,5]
[1]

猜测是删除了第1个节点引发的报错,更改示例如下

[1,2,3,4,5]
5
[1,2]
2

运行后出现新的报错

=================================================================
==43==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000030 at pc 0x55fd91f42904 bp 0x7ffe184c15b0 sp 0x7ffe184c15a0
READ of size 4 at 0x602000000030 thread T0
#2 0x7f9486376082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082)
0x602000000030 is located 0 bytes inside of 16-byte region [0x602000000030,0x602000000040)
freed by thread T0 here:
#0 0x7f9486fbe40f in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:122
#2 0x7f9486376082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082)
previously allocated by thread T0 here:
#0 0x7f9486fbea06 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:153
#4 0x7f9486376082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082)
Shadow bytes around the buggy address:
0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c047fff8000: fa fa fd fd fa fa[fd]fd fa fa 00 00 fa fa 00 00
0x0c047fff8010: fa fa 00 00 fa fa 00 00 fa fa 04 fa fa fa fa fa
0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==43==ABORTING

注释掉 free(del); 后再运行,输出错误结果

[1,3,4,5]

预期结果:[2,3,4,5]

[1]

预期结果:[2]

显然猜测正确

参考力扣官方给出的题解,前言中提到“头节点不存在前驱节点,需要在删除头节点时进行特殊判断”,这类题目通常做法是在头节点前“添加一个哑节点(dummy node)”,再参考力扣的视频题解得知,该题给出的链表不设置空的头节点,链表的头节点中直接存放第一个元素
链表结构
而错误代码编写时将链表的头节点作为一个空节点计算,代码在删除链表倒数第 n 个节点时删除的是第 2 个节点(如上图存放 2 的节点),而执行 free(del) 后又将第一个节点(head)的内存释放掉,使得返回的头节点为已被释放掉的内存,导致报错

3.2 寻求解决方法

由于头节点不存在前驱节点,仅存在指向头节点的指针,因此需要对删除头节点的情况进行特殊判断

// 删除节点
if(beforedel == del){
    head = del -> next; // del -> next 或 beforedel -> next 均可
}
else{
    beforedel -> next = beforedel -> next -> next;
}
free(del);

输出正确结果
输出
开销
开销

4 最终结果

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
    int distance = 0;   // 计数器
    struct ListNode *end = head, *del = head, *beforedel = head;

    // 定位删除的节点
    while(end){
        if(distance < n){
            ++distance;
        }
        else{
            beforedel = del;    // 定位删除节点前的节点
            del = del->next;
        }
        end = end->next;
    }

    // 删除节点
    if(beforedel == del){
        head = del -> next; // del -> next 或 beforedel -> next 均可
    }
    else{
        beforedel -> next = beforedel -> next -> next;
    }
    free(del);

    return head;    
}

5 总结

删除链表节点问题需要先确定给出链表的头节点是否存放了数据。对于头节点中存在数据的链表,需要另外考虑删除头节点的情况

官方题解采用添加哑节点的方法能让过程更简洁一些,在内存消耗方面也更占优势
官方题解开销

标签:00,19,倒数第,链表,fa,del,next,节点,beforedel
From: https://www.cnblogs.com/guanz/p/17783513.html

相关文章

  • 每日总结10.19
    今天的一天过得非常充实,我参加了各种不同的课程和准备了一次令人兴奋的旅行。上午,我上了UML建模语言的课程,这是软件工程中非常重要的一部分,它帮助我们理解了如何设计和规划软件系统。之后,我参加了体育课,学习了乒乓球的正手和反手技巧。这是一种有趣的锻炼,也有助于保持身体健康。......
  • 文心一言 VS 讯飞星火 VS chatgpt (119)-- 算法导论10.3 4题
    四、用go语言,我们往往希望双向链表的所有元素在存储器中保持紧凑,例如,在多数组表示中占用前m个下标位置。(在页式虚拟存储的计算环境下,即为这种情况。)假设除指向链表本身的指针外没有其他指针指向该链表的元素,试说明如何实现过程ALLOCATE-OBIECT和FREE-OBJECT,使得该表示保持紧凑......
  • Day19_叠加多个装饰器_生成器_三元表达式_列表、字典、集合生成式_生成器表达式
    1.叠加多个装饰器运行顺序: 2.生成器的运行: 3..send()方法可以为yield传输返回值: 4..send()一个None相当于把None添加到yield后: 5..close关闭之后无法传值: 6.三元表达式: 7.列表生成式: 8.字典生成式: 9.集合生成式: 10.生成器表达式: ......
  • 在使用Windows Server 2019 (1809)的EC2上安装WSL运行Ubuntu Linux
    一、背景在Windows10上可以使用WSL和新的Terminal直接运行Linux,同时,还可以通过WindowsStore在线商店安装需要的Linux发行版。但在WindowsServer上,没有在线商店可用。因此,安装方法可以参考如下。首先检查确认版本高于WindowsServer2019(version1709)版本。例如EC2上选择......
  • 【ZJCTF 2019】NiZhuanSiWei
    [ZJCTF2019]NiZhuanSiWei收获file_get_contents绕过include联想伪协议熟悉__tostring魔术方法的使用题目代码:<?php$text=$_GET["text"];$file=$_GET["file"];$password=$_GET["password"];if(isset($text)&&(file_get_contents(......
  • 2023.10.19
    1.0版本生成四则运算并存入数据库importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOE......
  • 编程导航算法通关村第 1 关 | 链表
    1.前置知识补充内容引用:https://www.hello-algo.com/数据结构数据结构如同一副稳固而多样的框架。它为数据的有序组织提供了蓝图,使算法得以在此基础上生动起来。分类1.根据逻辑类型分类逻辑结构揭示了数据元素之间的逻辑关系。在数组和链表中,数据按照顺序依次排列,体现......
  • 2023-2024-1 20231319《计算机基础与程序设计》第四周学习总结
    2023-2024-120231319邓传山《计算机基础与程序设计》第3周学习总结作业信息这个作业属于哪个课程2023-2024-1-计算机基础与程序设计这个作业要求在哪里https://www.cnblogs.com/rocedu/p/9577842.html#WEEK01这个作业的目标学习《计算机科学概论(第7版)》第4、5章......
  • 2023-2024-1 20231419 《计算机基础与程序设计》第四周学习总结
    2023-2024-120231419《计算机基础与程序设计》第四周学习总结作业信息这个作业属于哪个课程https://edu.cnblogs.com/campus/besti/2023-2024-1-CFAP这个作业要求在哪里https://www.cnblogs.com/rocedu/p/9577842.html#WEEK04这个作业的目标预习《计算机科学概......
  • 面试必刷TOP101:9、删除链表的倒数第n个节点
    一、题目二、题解2.1双指针由于我们需要找到倒数第n个节点,因此可以使用两个指针fast和slow同时对链表进行遍历,并且fast比slow超前n个节点。当fast遍历到链表的末尾时,slow就恰好处于倒数第n个节点。具体地,初始时fast和slow均指向头节点。首先使用fast对链表......