LeetCode 82,考察你的基本功,在有序链表中删除重复元素II

链表递归算法精解:从反转、合并到LeetCode实战 递归是计算机科学中一种核心的编程思想,它将复杂问题分解为结构相似的子问题,通过函数自我调用来解决。其基本原理在于定义明确的递归基(终止条件)和递归逻辑,相信函数能正确解决更小规模的子问题,并基于子问题的解构建原问题的答案。这种分而治之的思想在算法设计中具有极高的技术价值,能大幅简化代码逻辑,尤其在处理具有自相似结构的数据时。在数据结构领域,链表作为一种线性序列,其节点指向下一个节点的特性,天然契合递归的思维模型。这使得递归成为解决链表问题的强大工具,广泛应用于链表反转、有序链表合并、节点删除与查找等经典场景 阅读详情

本文始发于个人公众号:TechFlow,原创不易,求个关注


今天是LeetCode专题的第51篇文章,我们来看LeetCode第82题,删除有序链表中的重复元素II(Remove Duplicates from Sorted List II)。

这题官方给出的难度是Medium,点赞1636,反对107,通过率在36.3%左右。根据我们之前的分析,这题的难度适中,并且质量很高,好评如潮。实际上也的确如此,这题算法本身并不难,但是想要完整没有bug地实现并不容易,我们一起来看看。


题意


给定一个有序的存在重复元素的链表,要求移除掉链表当中所有的重复元素。返回一个不包含重复元素的链表。

这里要注意的一点,这题让我们做的事情并不是去重,就是去除掉多余的元素,而是要去除掉所有重复的元素。比如2在链表当中出现了两次,属于重复元素,我们要做的并不是去掉一个2,仅保留一个,而是要将所有的2都去除,因为2属于重复元素。

我们来看样例:

Input: 1->2->3->3->4->4->5
Output: 1->2->5

原链表当中的3和4都属于重复元素,所以被去除了。

Input: 1->1->1->2->3
Output: 2->3

解法


前面说了这题的质量很高,这题是属于典型的解法赤裸裸,但是很多人就是写不出来的题,非常考察基本功。适合用在校招面试当中,如果我有幸去面试校招生, 我可能会选这道题。不存在算法会不会的问题,写不出来一定是基本功不够扎实。

链表已经有序了,那么相同的元素必然会排在一起,我们只需要将它们移除就可以了。但是说起来简单,要在链表当中实现并不容易。难点主要有两个,一个是链表增删节点的操作很多人不熟悉,尤其是像是C++这样的语言涉及指针,可能更不容易。另外一个难点就在题意当中,我们要做的不是去重,而是要所有重复的元素全部删除。

看起来似乎和去重没什么差别, 如果你真这么想,并且着手去实现,那么几乎可以肯定一定会遇到问题。

因为链表是单向的,假设你当前的指针是cur,当你发现cur这个指针的元素存在重复的时候,你需要连当前这个节点一起删除。我们都知道,单向链表是不能走回头路的,而删除节点,必须要用到前一个节点的指针。再加上判断元素重复需要用到的指针,会需要我们同时维护多个指针,增加代码的编码难度。

针对这个问题,我们有两种解决思路。第一种是我们不在原链表上处理,而是创建一个新的链表进行返回。所以我们要做的就不是删除元素,而是插入元素,只有发现当前元素不存在重复的时候才会插入链表。最后返回的也是一个全新的链表。

这当然是可以的,也是没有问题了,我第一次做这道题就是采取的这种措施。相比之下, 这种方法会容易一些,因为我们不需要判断太多的指针和位置,我贴一下当时的代码:

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
          // 如果元素少于2个则直接返回
        if (head == nullptr || head->next == nullptr) return head;
        int cur = head->val;
          // 初始化
        bool flag = false;
        ListNode* ct = new ListNode(0);
        ListNode* pnt = ct;
        head = head->next;
          // 遍历元素
        while (head) {
            int hd = head->val;
               // 判断当前元素与之前的元素是否相等
            if (hd != cur) {
                   // 之前的元素没有出现重复
                if (!flag) {
                       // 把之前的元素存入链表
                    pnt->next = new ListNode(cur);
                       // 链表移动
                    pnt = pnt->next;
                }else flag = false;
                   // 更新之前的元素
                cur = hd;
            }else flag = true;
            head = head->next;
        }
          // 单独处理最后一个元素
        if (!flag) pnt->next = new ListNode(cur);
        return ct->next;
    }
};

虽然题目当中没有对解法做出限制,也没有规定我们必须要在原链表上进行处理,但是这种创建新链表的方法终归有绕开问题的嫌疑。所以我们还有第二种解法,就是直面问题,我们维护多个指针,判断当前位置的下一个元素是否构成重复。如果重复,则删除掉重复的部分。

正如我们之前所说的那样,在单向链表当中很难删除当前元素,所以我们判断下一个元素是否会构成重复。如果重复的话,进行删除要可行许多。这样也有一个问题就是,有可能链表的第一个元素就是重复的,我们没有办法找到第一个元素的上一个元素。针对这个问题,我们采用的方法是人为给它创造一个元素放在首元素之前。这样我们整个流程就可以串起来了,唯一的难点就是编码了。

我们仔细一些,写出代码还是可以的:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
        # 创建一个新的元素放在链表头部,这样原本第一个元素就是头指针的下一个元素了
        node = ListNode()
        node.next = head
        # pnt指向新创建的元素
        pnt = node
        
        while pnt.next is not None:
            # cur指向当前位置的下一个位置
            # 我们要做的即判断cur这个指针的元素是否重复
            cur = pnt.next
            if cur.next is None:
                break
             
           	# ptr指向cur的next
            ptr = cur.next
            # 如果ptr和cur相等,那么出现重复,我们需要跳过所有相等的元素
            if ptr is not None and ptr.val == cur.val:
                while ptr is not None and ptr.val == cur.val:
                    ptr = ptr.next
                pnt.next = ptr
            # 否则说明不重复,移动pnt
            else:
                pnt = pnt.next
                
        # 由于我们开始的时候人为添加了一个辅助元素
        # 返回的时候要将它去除
        return node.next

总结


这道题的算法很简单,我想大部分人都能想出解法来,但是要将解法实现并不太容易。这当中用到了很多小技巧,比如我们认为创建了一个新的头结点,比如我们将删除当前元素转化成了删除下一个元素等等。这些技巧虽然算不上什么,但是灵活使用,可以大大降低我们编码的复杂度,也正是因为这一点,这题的质量非常高,值得一做。

很多人非常讨厌涉及链表的问题,觉得链表很难操作,容易写错,但实际上这是基本功的很重要的一部分。很多公司喜欢考察候选人的基本功,提升这方面的能力对于我们应聘或者是工作非常有帮助。

今天的文章到这里就结束了,如果喜欢本文的话,请来一波素质三连,给我一点支持吧(关注、转发、点赞)。

在这里插入图片描述

2024字节社招测试开发岗一面、二面、三面、交叉面面经 注:我没有在帖子里写明具体是面试的哪个部门。讲一个项目Es和MySQL区别,什么时候用API鉴权、限流;为啥用HTTP接口,不用RPC接口讲所负责的专项建设工作压测做过多少?答:说压测不是我主要负责的方向,就没有细问了职业规划。 阅读详情

相关推荐

【华为OD技术面】 - 考到的Lettcode手撕算法代码真题目录

【华为OD技术面 - 考到的Lettcode手撕算法代码真题目录

算法大师! 7807

LeetCode第82题

给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中没有重复出现的数字。 先考虑的是最简单的情况,假如是空链表,或者链表中只含有一个节点,这种情况下无需比较,直接返回即可。 除此以外,需要逐步比较,设置两个节点,但实际上是两个节点的next指向链表中的节点,这样是为了删除方便,毕竟只是单链表,无法回溯。 class Solution { public ListNode deleteDuplicates(ListNode head) { // 若链表为空,或只有一个节点

waldeinNJU的博客 646

跨厂商网络设备的RADIUS认证:Windows NPS的兼容性与最佳实践

本文详细探讨了Windows NPS在多厂商网络环境中的RADIUS认证实践,特别针对华为、华三、思科等主流设备的兼容性问题提供解决方案。从基础配置到高级优化,涵盖VSA属性映射、认证协议选择及安全加固措施,帮助企业实现统一身份认证并提升网络安全性。

weixin_29213827的博客 420

LeetCode82 删除排序链表中的重复元素

Question 给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。 方法一 当然是递归大法 当head后面有值并且和head的值相等,则一直找到与head不相等为止,然后对后面一个结点去递归,这样就删除了前面重复的结点 当head后面有值且与head的值不相等时,那么就递归后面一个结点,跟在head后面 最后返回head 思路还是很简单的,代码如下: /** * Definition for singly-linked list.

qq_51553911的博客 1224

基于DBSCAN聚类算法的超像素实时分割

Real-Time Superpixel Segmentation by DBSCAN Clustering Algorithm 摘要 在本文中,我们提出了一种基于密度的带噪声应用空间聚类(DBSCAN)算法的50帧/秒实时图像超像素分割方法。为了降低超像素算法的计算量,我们采用了一种快速的两步框架。在第一个聚类阶段,使用具有颜色相似性和几何约束的DBSCAN算法对像素进行快速聚类,然后在第二个合并阶段,通过颜色和空间特征定义的距离度量,将小簇按其邻域合并为超像素。为了在这两个步骤中获得更好的超像素,定义了

yttt的博客 3492

Grafana图像渲染插件安装全攻略:解决依赖缺失问题(附完整命令清单)

本文详细介绍了在CentOS/RHEL环境下安装Grafana图像渲染插件`grafana-image-renderer`的全过程,包括解决常见的依赖缺失问题。通过提供完整的命令清单和疑难问题排查指南,帮助用户高效部署和优化插件性能,确保图像渲染功能稳定运行。

weixin_30399821的博客 84

LeetCode第82题_删除排序链表中的重复元素II

给定一个已排序的链表的头head,删除原始链表中所有重复数字的节点,只留下不同的数字。返回已排序的链表。

qq_40263592的博客 1410

ESP32C6+ESP-IDF5.2实战:基于RS485的ModbusRTU从站开发与调试

本文详细介绍了基于ESP32C6和ESP-IDF5.2开发ModbusRTU从站的实战指南。涵盖硬件连接、协议实现、ESP-Modbus库移植、寄存器映射及调试技巧,帮助开发者快速构建稳定可靠的工业级RS485通信节点,并解决常见通信故障。

play7的博客 1188

数据结构之线性表——LeetCode:82. 删除排序链表中的重复元素 II,21. 合并两个有序链表,23. 合并 K 个升序链表

这段代码的目的是合并两个升序链表为一个新的升序链表。它通过比较两个链表当前节点的值,将较小值的节点依次连接到新链表中,直到其中一个链表遍历完,然后将剩余的链表连接到新链表的末尾。

u014114223的博客 1298

深入解析CAN2.0A与CAN2.0B协议:帧格式与通信机制对比

本文深入对比了CAN2.0A与CAN2.0B协议的核心差异,重点解析了11位标准帧与29位扩展帧的帧格式、标识符长度及通信机制。文章阐述了CAN2.0B向下兼容的特性,并探讨了在汽车电子、工业控制等复杂网络中,如何根据项目需求、兼容性及实时性要求,在标准帧与扩展帧之间做出合理选择。

weixin_29163797的博客 392

Lumerical FDTD新手必看:从零开始搭建光子晶体仿真环境(附完整脚本)

本文为Lumerical FDTD新手提供光子晶体仿真环境的完整搭建指南,涵盖从基础参数设置到脚本编写的全流程。通过典型光子晶体带隙分析案例,详细讲解结构建模、仿真参数配置及后处理技巧,并附赠完整MATLAB脚本,帮助用户快速掌握FDTD仿真核心技术。

3c4x5z6v7b的博客 1050

leetcode82删除排序链表中的重复元素

上面就是如果头结点与它的next结点的值一样,那么就把这个头结点的next交给move结点,然后内部循环是否继续相等,知道不相等的时候跳出循环,继续以move为头结点进行递归,一旦到了一个与next不相等的位置,那么就把这个当前move指针的next继续下面递归,直到最后next等于NULL时候,停止递归,开始返回数据。那么最早的头一定是最晚返回的数据,所以最后的head,一定就是头结点了。外部循环判定卡住的位置。好了,祝大家早安午安晚安。具体分析一下指针移动。

Pxx520Tangtian的博客 278

【系统架构设计师-2024下半年真题】案例分析-参考答案及部分详解(完整回忆版)

根据h中描述,为了保证高可靠性,有ping/echo,心跳机制两种策略,从资源利用率问为啥心跳更好。王工觉得使用ping/echo好,但李工觉得从系统资源利用率来说,使用心跳机制好 1、针对质量属性可以使用ping/echo和心跳模式实现,分别简述ping/echo和心跳的实现原理。 2、张工认为心跳策略比较适合,简述为什么?

数据知道的博客 1万+

写出一段代码将链表中的两个节点位置互换位置_LeetCode 82,考察你的基本功,在有序链表中删除重复元素II...

本文始发于个人公众号:TechFlow,原创不易,求个关注今天是LeetCode专题的第51篇文章,我们来看LeetCode第82题,删除有序链表中的重复元素II(Remove Duplicates from Sorted List II)。这题官方给出的难度是Medium,点赞1636,反对107,通过率在36.3%左右。根据我们之前的分析,这题的难度适中,并且质量很高,好评如潮。实际上也的确如...

weixin_39755890的博客 181

FPGA设计-Vivado的Off-Chip Termination设置问题

经常遇到在FPGA设计时,很多人很迷惑这些关于硬件的终端匹配怎么设置,Vivado的Off-Chip Termination设置问题,这里就详细说一下这个问题。

whm128的博客 2721

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

82. 删除排序链表中的重复元素 II

本文介绍了一种删除排序链表中所有重复元素的算法。通过设置哑节点作为辅助头节点,使用pre和cur双指针遍历链表。当发现重复节点时,跳过所有重复项,将前驱节点直接指向非重复节点;否则正常移动指针。该方法时间复杂度为O(n),空间复杂度O(1),能有效处理各种重复情况,包括删除头节点的情况。关键点在于利用哑节点统一处理逻辑,并通过临时next节点判断重复范围。

mrjieke6的博客 614

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

​LeetCode刷题实战82:删除排序链表中的重复元素 II

算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试。所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 ...

程序IT圈 298

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

彻底删除重复节点——LeetCode 82 题「有序链表去重 II」详解

LeetCode 82 题考验的是对链表指针的精细控制和对边界条件的全面考虑。通过引入虚拟头节点和谨慎移动前驱指针,我们可以优雅地解决“彻底删除重复节点”的问题。掌握此类题型,不仅有助于面试,更能提升对链表这一基础数据结构的理解。当需要删除头节点或处理复杂连接时,dummy node 是你的最佳伙伴。编程如织网,指针似针线——唯有细致穿引,方得清晰结构。

2609_95039045的博客 394

力扣刷题笔记

目录1 数组1.1 867. 转置矩阵二级目录三级目录 1 数组 1.1 867. 转置矩阵 867. 转置矩阵 tips:方阵时候的快速处理。 二级目录 三级目录

你佳哥 467

大厂社招3年-力扣热点高频刷题记录(已更新100+道热点题)

前言: 最近从在大厂出来看机会,大厂面试基本都考察算法,于是维护此文档,一是查缺补漏,确保整体热点算法题目的应知应会,与思路的灵活理解;二是分享出来给其他同学朋友做一个参考借鉴,共同学习成长 目前刷题方向侧重于各大厂热点题,以及力扣的Hot 100 此笔记持续更新。 文章目录一、菜单未分类树栈回溯二分双指针双指针DP贪心二、刷题记录1. 两数相加——哈希——一刷2. 两数相加——链表——二刷3. 无重复字符的最长子串——滑动窗口——三刷5.最长回文串——数组11. 盛水最多的容器——双指针——二刷15. 三

weixin_43899069的博客 3668

几乎刷完了力扣所有的链表题,我发现了这些东西。。。

转自:https://leetcode-cn.com/circle/article/Ej98dm/ 以上就是我们给大家的四个技巧了。相信有了这四个技巧,写链表题就没那么艰难啦~ ^_^ 题目推荐 最后推荐几道题给大家,用今天学到的知识解决它们吧~ 21. 合并两个有序链表 82. 删除排序链表中的重复元素 II 83. 删除排序链表中的重复元素 86. 分隔链表 92. 反转链表 II 138. 复制带随机指针的链表 141. 环形链表 142. 环形链表 II 143. 重排链表 148. 排序链表

LTCM_SAKURA的博客 296

LeetCode 刷题汇总(第一阶段,随机游走)

从 0 开始 LeetCode刷题 面临毕业,为了谋求一份工作,不得已走上了刷题之路。不追求解法的性能和代码的优雅,只追求在最短的时间内写出来。 很多人喜欢给各种各样的方法起一个奇奇怪怪的名字,比如说“回溯”、“滑动窗口”等等,不懂这些,也可以做呀。你最后自己想了一个方法做出来了,其实默默地也就用了这些所谓的方法。这些题目我做完了,别人和我聊起什么回溯,我也不懂什么意思。我只知道,暴力出奇迹,干就完了。 我们做计算数学的人的长处不在于刷题,奈何这个世界这么无奈。 其实,我一直在思考,用这些小算法题去考验一

LSEC小陆的博客 1151

一文通数据结构与算法之——链表+常见题型与解题策略+Leetcode经典题

文章目录1 链表1.1 常见题型及解题策略1.1.1 LeetCode中关于链表的题目有以下五种类型题:1.1.2 解题策略1.2 链表的基本内容1.2.1 链表的基本结构:1.2.2 插入新元素1.2.3 删除某个元素1.2.4 遍历单链表1.3 删除链表结点类题目1.3.1 题解方法1.3.2 可能出现的问题1.3.3 题库列表:237、删除链表中的节点203、移除链表元素剑指 Offer 18. 删除链表的节点面试题 02.01. 移除重复节点82. 删除排序链表中的重复元素 II19、删除链表的倒

尚墨1111的博客 629

【算法训练营 · 二刷总结篇】链表、哈希表部分

链表是后端面试的高频考点,核心考察点包括:链表结构特性(非连续存储、高效增删)、虚拟头节点简化边界处理、快慢指针解决环和中点问题、递归实现反转等操作。重点技巧包括虚拟头节点法(60%题目适用)、快慢指针法(找中点/判环)、递归法(优雅实现反转),以及双指针遍历和哈希表辅助法。典型应用场景涵盖LRU缓存、HashMap冲突处理等实际业务。面试需特别注意边界条件处理(空链表、单节点、头尾节点操作)和空间时间复杂度优化。

十八岁讨厌编程的博客 693

腾讯后端高频面试题 Love 6 刷题合集(第一轮)

文章目录前引后端面试题 刷题博客合集(持续更新中) 前引 鉴于力扣我已经刷了六百多道了 当我是分专题做的 二分查找 贪心算法 动态规划 回溯算法 二叉树 DFS BFS 类似还有很多的算法 绝大部分我都已经做过了 在大概刷了半年多的题后 我也决定在今天之后开始 彻底总攻腾讯后端面试题了 于是在此开一篇博客 来记录我写的每一道后端面试高频考题 附上一张 开始刷题时 力扣的刷题页面吧 后端面试题 刷题博客合集(持续更新中) 146. LRU 缓存机制(手撕双向链表) ...

Love 6's Private Blog 1057

LeetCode82_删除排序链表中的重复元素Ⅱ

链表 & 双指针

Haolin_Liu的博客 333
上一篇: golang | Go语言入门教程——结构体初始化与继承
下一篇: 面经 | 我在大学里拿了XXX大赛的X等奖,可以写进简历吗?
TechFlow
博客等级 码龄7年 347粉丝 276原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值