LeetCode——237.Delete Node in a Linked List

本文探讨了在单链表中删除指定节点的有效方法,特别是当仅提供目标节点的访问权限时。通过实例展示了如何绕过传统方法,利用节点值和引用覆盖实现删除,为链表操作提供了一种新颖的解决方案。

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

237.Delete Node in a Linked List

  • 问题描述
    编写一个函数来删除单链表中的一个节点(除了尾部),只给出对该节点的访问。

    给定链表-Head=[4],[5],[1-9],如下所示:

   4 -> 5 -> 1 -> 9
Input: head = [4,5,1,9], node = 5
Output: [4,1,9]
Input: head = [4,5,1,9], node = 1
Output: [4,5,9]
  • 思路解法
    1.链表由结点构成,Java需要创建结点对象,对象属性有结点值,和下一个结点的引用。

    2.知道要删除的结点时,由于改链表是单向链表,只能知道该节点的下一个结点,因此不能用该节点的上一个结点的引用,指向该节点的下一个结点。

3.由于知道了该节点的信息我们就可以得到该节点之后的所有结点的信息,我们可以不用直接删除该节点,或者说删除不了该节点,但我们可以删除下面的结点,所以让该节点对象里的值和下一个几结点的对象引用被该节点的下一个结点覆盖后,再删除该节点的下一个结点,就能完成任务。

  • 代码

java

    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) { val = x; }
     * }
     */
    class Solution {
        public void deleteNode(ListNode node) {
            node.val=node.next.val;
            node.next=node.next.next;
        }
    }
  • 总结
    1.对于链表的结点删除操作有很多方法,其中包括知道删除的结点的前一个结点的引用,直接将该节点的下一个结点的引用赋值要删除的结点的前一个结点的引用。

2.对于该类题目给我们提供了删除结点的其他思路

<think>好吧,我现在要解决的问题是删除链表中的一个节点,但给定的函数参数只有要删除的节点本身,而不是链表的头节点。这看起来有点挑战性,因为我不能直接遍历链表找到前一个节点。让我仔细想想应该怎么做。首先,题目给出的链表结构是这样的,每个节点有一个val和一个指向下一个节点的next指针。函数deleteNode的参数是一个ListNode*node,也就是需要被删除的那个节点。通常删除链表节点的方法是需要知道前一个节点,然后将前一个节点的next指向当前节点的下一个节点。但这里没有头节点,所以常规方法行不通。那怎么办呢?我想到了可能的方法是把当前节点的值和指针都替换成下一个节点的。比如,假设要删除的节点是A,下一个节点是B。那么,我们可以把A的值设置为B的值,然后把A的next指向B的下一个节点。这样,实际上相当于把B的内容复制到A,然后跳过了B。这样,原来的A节点就变成了B节点的内容,而B节点就被删除了。这种方法的好处是不需要知道前一个节点,只需要操作当前节点和下一个节点即可。不过需要注意的是,这个方法的前提是当前节点不是链表的尾节点。因为如果是尾节点的话,就没有下一个节点可以复制了。但题目中可能已经假设了要删除的节点不是末尾节点,或者题目保证输入的节点不会是尾节点。比如,在LeetCode的类似问题中,通常会给出这样的条件。所以在这种情况下,这种方法是可行的。 那具体怎么实现呢?假设当前节点是node,那么node->next存在。这时候,可以将node的val设置为node->next的val,然后把node的next指向node->next->next。这样就相当于跳过了下一个节点,达到了删除当前节点的效果。或者更直接一点,把当前节点的内存替换成下一个节点的。比如,用*node= *node->next;这样的代码。因为这样会把下一个节点的所有内容(包括val和next)都复制到当前节点,然后原来的下一个节点就被跳过了。不过这样做的话,原来的下一个节点的内存可能没有被释放,如果有动态分配的话可能会有内存泄漏。但题目中的链表可能没有要求释放内存,或者假设节点是动态分配的,由其他部分处理。在这种情况下,这种方法可以正确完成题目要求。那在代码中,原来的注释是//*node= *node->next;,只需要取消注释即可。或者,按照另一种方式,将node的val设为下一个节点的val,然后调整next指针。这两种方法其实是等效的。例如:node->val =node->next->val;node->next =node->next->next;这样写的话,可能更直观一些,而使用结构体赋值的方式可能更简洁。这两种方法都可行,但需要注意内存泄漏的问题。不过在这个问题中,可能不需要处理,因为题目可能接受这样的解法。 那么,正确的代码应该是这样的: classSolution {public:voiddeleteNode(ListNode*node){ListNode*nextNode= node->next;*node= *nextNode; //复制下一个节点的内容到当前节点//或者另一种写法:// node->val= nextNode->val;//node->next =nextNode->next;delete nextNode;//是否需要删除?原题可能没有考虑,但可能引起问题。} };不过,如果原题中的链表节点是动态分配的,并且我们确实需要释放内存的话,那么可能需要删除原来的下一个节点。但直接调用delete nextNode可能会导致问题,因为原链表中的其他节点可能还持有这个指针。例如,如果node是第二个节点,而第三个节点被删除,那么第二个节点的next指针已经被修改为第四个节点,但是第三个节点被delete了,这可能没问题?或者题目可能不要求释放内存,只调整结构即可。比如在LeetCode的测试用例中,可能只关注链表的结构是否正确,而不关心内存是否泄漏。所以在这种情况下,可能不需要delete操作,直接修改指针即可。比如,原题给出的代码中的注释行是直接解引用了node->next赋值给*node。这可能将下一个节点的所有内容复制到当前节点,包括val和next指针。这样,当前节点就变成了下一个节点的内容,而原来的下一个节点就被跳过了。这样,原来的下一个节点实际上没有被删除,但它的内容已经被复制到当前节点,所以链表的结构是正确的。不过,这种情况下,原来的下一个节点可能没有被释放,导致内存泄漏。但可能题目允许这样的做法,或者测试用例不检查内存泄漏。因此,正确的解决方案是使用结构体赋值或者修改val和next指针的方式,将当前节点的内容替换为下一个节点的内容,从而间接删除当前节点。这样不需要访问前一个节点,时间复杂度为O(1)。总结一下,问题的关键在于无法访问前驱节点,所以需要将当前节点的信息替换为下一个节点的,从而跳过下一个节点。这样,当前节点就变成了下一个节点的内容,而原来的节点被覆盖,从而达到了删除当前节点的效果。这种方法的时间复杂度是O(1),非常高效。</think>要删除链表中的指定节点(非末尾节点),可以通过复制下一个节点的值并调整指针来实现: ```cpp class Solution { public: void deleteNode(ListNode* node) { ListNode* nextNode = node->next; *node = *nextNode; // 关键操作:整体结构复制 delete nextNode; // 防止内存泄漏(根据题目具体要求决定是否保留) } }; ``` **解释**: 1. **核心思路**:题目给定的是要删除的节点本身而非头节点,因此无法通过常规的前驱节点操作来实现。这里采用将下一个节点的内容整体复制到当前节点的方法,使得当前节点在逻辑上被替换为下一个节点,从而间接完成删除操作。 2. **结构体赋值**:`*node = *nextNode` 会执行浅拷贝,将下一个节点的值和指针完整复制到当前节点,这样当前节点就继承了下一个节点的所有属性,等同于让当前节点变成下一个节点。 3. **内存管理**:`delete nextNode` 用于释放被跳过的原下一个节点的内存,但需要注意: - 如果题目中的链表节点不允许修改内存分配方式(如某些在线判题系统不检查内存泄漏),可以省略这一步 - 在真实工程场景中,必须确保没有其他指针指向这个被删除的节点
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值