删除链表中重复元素的问题

news2025/1/14 1:22:20

目录

一、删除所有重复元素,使每个元素只出现一次

1.1带头链表解法

1.2 递归方法

二、删除所有重复数字结点,只留下不同数字

2.1带头链表解法

2.2 递归方法 


一、删除所有重复元素,使每个元素只出现一次

给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回已排序的链表 。

1.1带头链表解法

首先,我们要排除链表为空的情况。另一种可以直接返回的情况就是头结点的后继节点为空,如果只有一个结点那么肯定不存在重复元素的问题, 所以以上两种情况可以直接返回head。

如何能知到哪个节点是重复结点,判断这一点一定会牵扯到两个结点之间的比较,如果prev.val == cur.val name说明prev和cur是两个重复的节点。

所以我们要创建一个带头链表dummyHead,使他的第一个数为-101(其实为多少都可以,因为这个结点是不进入循环判断的,判断的是他的后继节点)然后让dummyHead.next = head,使自己创建的带头链表和给的单链表做出联系。

已经判断过head和head.next非空,则使prev = dummyHead.next并且cur = prev.next。

prev指向的可以是第一个重复的节点,因为要保存它,也可以指向不重复的结点。cur就是要和prev判断的结点,如果两个值相等那么cur和prev.next就需要向后移,这个时候中间重复的结点就已经被删除了,这个过程会一直进行到cur和prev不再相等。

当移动到不相等的时候,prev 就可以移动了prev= prev.next,然后cur = cur.next,继续进行下一次判判断

最后只要返回dummyHead.next就能返回没有重复元素的链表了。

    public ListNode deleteDuplicates(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode dummyHead = new ListNode(-101);
        dummyHead.next = head;
        ListNode prev = dummyHead.next;
        ListNode cur = prev.next;
        while (cur != null) {
            if(prev.val == cur.val) {
                prev.next = cur.next;
            }else {
                prev = prev.next;
            }
            cur = cur.next;
        }
        return dummyHead.next;
    }

也可以直接使用单链表解法,不需要创建一个单独的虚拟头结点直接将prev指向head即可 ,其他相同。

1.2 递归方法

首先,也是要看链表为空的和头结点的后继节点为空的两种情况,此时不可能存在重复节点,直接返回链表的头结点即可。即是递归的结束条件也是特殊情况。

 然后需要先处理子链表,则让head.next = deleteDuplicates(head.next),由方法来判断head.next是哪个结点。

现在就可以处理当前头节点的情况,如果 head.val == head.next.val则return 第二个节点,第一个结点就直接删除了,只保留了一个重复地结点 。如果不相等那么return 第一个结点,然后第二个结点留着继续判断。

递归进行到最后是这样的,head.next==null。

所以则回到了上一层的递归,刚刚的head变成了head.next。

 这个时候进行判断,head.val == head.next.val 所以return head.next 把head删除了,只留下一个重复的元素。

 然后继续进行判断,head.val != head.next.val,所以head.next和head都保留了,return head。

 保留之后链表是这样的形态,然后继续进行递归。

    public ListNode deleteDuplicates(ListNode head) {
        // 1.base case
        if (head == null || head.next == null) {
            return head;
        }
        head.next = deleteDuplicates(head.next);
        return head.val == head.next.val ? head.next : head;
    }

二、删除所有重复数字结点,只留下不同数字

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

2.1带头链表解法

这种情况下不能使用单链表解法了,会更加困难,因为可能头结点也需要被删除,所以需要制造一个前驱结点,来判断前驱结点后面的结点需不需要被删除。

同样的我们要排除链表为空和头结点的后继节点为空的情况,以上两种情况可以直接返回head。

然后也是要创建一个带头链表dummyHead,使他的第一个数为-101,然后让dummyHead.next = head,使自己创建的带头链表和给的单链表做出联系。

但是这时我们需要使prev= dummyHead,不能让他为dummyHead.next,为了防止头结点也是重复元素而不被删除。

重复元素都必须被删除的情况下,我们需要比较两个元素的话,就需要创建两个变量cur和sec。使cur = prev.next(也就是让cur表示原链表的头结点),sec = cur.next。

 当cur和sec不相等的时候,证明cur在这个链表中没有重复元素(因为这个链表是有序的,后面都只会和他相同或者比他大,出现一个比他大的后面都比他大)那么prev就可以向后移动一位,然后cur和sec都跟着移动一位以及判断。(此处忽略cur移动到2,直接将cur移动到第一个3,sec移动到第二个3,来进行重复元素的操作)

 现在sec.val == cur.val,所以我们我们不能动prev和cur,需要将sec继续向后移动,接着判断所以我们要使用while循环,并且循环的终止条件就是sec==null,因为sec总是先移动当他为空的时候没有具体值了循环就结束了,或者是sec.val != cur.val的时候进行下一步判断。

当循环结束后,sec和cur不再是重复的元素,但是也不能保证呢过sec和后面的不会重复所以prev还是不能动,但是prev的后继结点可以变为sec,这种情况下就已经删除掉中间重复的元素了。然后cur也变为sec,sec变为cur的后继结点,继续接下来的判断。

 这个时候cur和sec又相等了 所以重复进行上述操作。

 这个时候sec==null了,所以整个链表中已经不存在重复元素了,所以结束循环,直接返回dummyHead.next就能得到修改后的链表了。

    public ListNode deleteDuplicates(ListNode head) {
        if(head == null||head.next== null){
            return head;
        }
        ListNode dummyHead = new ListNode(-101);
        dummyHead.next = head;
        ListNode prev = dummyHead;
        ListNode cur = prev.next;
       while(cur!= null){
           ListNode sec = cur.next;
           if(sec == null){
               break;
           }
           if(cur.val!= sec.val){
               prev = prev.next;
           }else {
               while (sec!=null&&sec.val == cur.val){
                   sec = sec.next;
               }
               prev.next = sec;
           }
           cur = sec;
       }
        return dummyHead.next;
    }
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

2.2 递归方法 

首先,也是要看链表为空的和头结点的后继节点为空的两种情况,此时不可能存在重复节点,直接返回链表的头结点即可。即是递归的结束条件也是特殊情况。

然后就要判断当前头节点和第二个节点是否相等的问题,如果head.val != head.next.val,那么头结点不是要删除的节点则直接处理子节点的删除,head.next = deleteDuplicates(head.next),然后返回head。

如果头节点就是待删除的节点,就需要先把头节点处理完毕,就用到一个变量newHead使他等于head.next,然后进行while循环,判断newHead != null && newHead.val == head.val,只有在这种情况下newHead需要继续向后移,直到while循环走出则newHead是第一个不和head值相等的结点,那么前面的结点都需要删除,所以return deleteDuplicates(newHead)。继续进行递归。

 刚开始进行递归的时候是如下图的,head和newHead的值不相等,所以进入deleteDuplicates(head.next),不删除head。

 下一步的时候head和newHead的值仍然不相等,所以进入deleteDuplicates(head.next),不删除head。

 到这一步 head和newHead的值相等了,所以进入else语句中。并且满足while循环的条件,那么newHead就会向后移动一个。

移动之后newHead和head的值不相同了所以走出循环,return deleteDuplicates(newHead),则直接删除了这两个相同的结点,直接让值为2的结点的后继节点为新的newHead。

 走到这一步第一对重复结点已经被删除了,然后继续进行递归就能得到最后的结果。

    public ListNode deleteDuplicates(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        if (head.val != head.next.val) {
            head.next = deleteDuplicates(head.next);
            return head;
        }else {
            ListNode newHead = head.next;
            while (newHead != null && newHead.val == head.val) {
                newHead = newHead.next;
            }
            return deleteDuplicates(newHead);
        }
    }
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/19325.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android App开发实战项目之模仿美图秀秀的抠图工具(附源码 简单易懂 可直接使用)

需要图片集和源码请点赞关注收藏后评论区留言~~~ 所谓抠图神器,就是从一副图片中扣出用户想要的某块区域 一、需求描述 美图的修图功能如此强大,离不开专业的图片加工技术,抠图便是其中重要的一项功能。在App界面底部点击抠图按钮&#xff…

mysql查询:行转列与列转行

目录 1. 行转列 1.1 什么是行转列 1.2 准备工作 1.3 行转列的实现原理 2. 列转行 2.1 什么是列转行 2.2 准备工作 2.3 列转行的实现原理 3. 总结 1. 行转列 1.1 什么是行转列 从表面理解,就是表里存储在行上的数据,在查询结果里展示在列上面。举…

基于stm32单片机随机数自动摇号抽奖系统

资料编号:099 下面是相关功能视频演示: 99-基于stm32单片机随机数自动摇号抽奖系统(源码仿真全套资料)采用stm32单片机作为主控,LCD1602显示,通过按键来重置生成随机数,类似于摇号和抽奖系统 …

如何实现广义的元交易(Meta Transaction)

在合约内启用元交易是一个强大的补充。要求用户持有ETH来支付Gas一直以来都是而且仍然是新用户进入的最大挑战之一。如果只是简单的点击,谁知道现在会有多少人在使用以太坊? 但有时,解决方案可以在你的合约中加入元交易能力。实现起来可能比你想象的要容易。 什么是元交易?…

(带你分分种学会linux的文件类型和软硬链接)linxu的文件类型(硬链接和软链接详解)

文章目录一,时区部分1,时区状态的展示2,列出所有时区二,linux的文件类型1,列出目录和文件类型2,查看文件类型和状态并且修改用户密码3,文件类型表4,文件的三次修改时间三,linux的软硬…

记录Manjaro Linux安装nvidia显卡驱动失败的经历

我的Manjaro: 2022.11.19的最新系统,通过manjaro-kde-21.3.7-220816-linux515.iso安装,然后通过pacman -Syyu更新的我的设备: CPU intel 12700H,大小核架构,使用系统默认的linux5.15内核会发现启动firefox浏览器的速度…

LeetCode 142. 环形链表 II

题目链接:https://leetcode.cn/problems/linked-list-cycle-ii/ 思路如下: 用两个指针 fast, slow 同时从起点开始走,fast 每次走两步,slow 每次走一步。 如果过程中 fast 走到 null,则说明不存在环。否则当 fast 和…

基于Python3.6配置开发环境

前言 最近在CTF上遇到了瓶颈,本人不会python,导致有些题做不出来。而且python的实用性实在太强了,所以就找了一个培训机构的课程边学习边实践。现将经验总结,分享给大家。 正文 1、配置python安装路径和环境变量 怎么下载pyth…

【Acwing】最短路+二分 通信线路

340. 通信线路 - AcWing题库 题意: 思路: 首先因为贪心,免费升级的肯定是最贵的那几根 因此这道题可以简化为: 给定一张图,求结点1到结点N的所有路径中第K1大的边权的最小值 可以发现我们要求剩下的边中最大值的最…

Qt程序打包成安装包exe

本章介绍把Qt开发的程序打包成安装包的方法,程序打包成install.exe,可双击安装,有默认安装路径,也可以选择安装目录,自动生成桌面快捷方式和开始菜单选项,可以在操作系统–>设置–>应用程序里看到&am…

【响应式布局】使用 flexbox 实现简单响应式布局

场景和需求 屏幕 > 540px&#xff0c;前两个部分展示两列&#xff0c;屏幕 < 540px&#xff0c;前两个部分展示一列屏幕 < 540px&#xff0c;第一部分要反转展示屏幕 > 769px&#xff0c;第三个部分展示三列屏幕 < 769px&#xff0c;第三个部分展示一列 效果图…

java计算机毕业设计自习室管理系统(附源码、数据库)

java计算机毕业设计自习室管理系统&#xff08;附源码、数据库&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目…

java进阶编程思想(七天)

编程核心思想基本框架第一天&#xff08;继承&#xff09;第二天&#xff08;抽象和接口&#xff09;第四天&#xff08;多态、DATA、Object、正则&#xff09;第五天&#xff08;遍历、Set、斗地主游戏案例&#xff09;第六天第七天b站链接:懂不懂我意思明不明白哈哈哈基本框架…

声明式事务@Transactional

事务 事务管理在 Web 系统开发中是非常重要的&#xff0c;可以在一定程度上保证数据的一致性。Spring提供了非常优秀的事务管理机制&#xff0c;主要分为&#xff1a; 编程式事务声明式事务 编程式事物 在代码中手动的管理事务的提交、回滚等操作&#xff0c;代码侵入性比较…

【毕业设计】66-基于物联网技术的智能家居系统的研究(仿真工程、原理图、低重复率设计文档、答辩PPT)

【毕业设计】66-基于物联网技术的智能家居系统的研究&#xff08;仿真工程、原理图、低重复率设计文档、答辩PPT&#xff09; 文章目录【毕业设计】66-基于物联网技术的智能家居系统的研究&#xff08;仿真工程、原理图、低重复率设计文档、答辩PPT&#xff09;资料下载链接任务…

代码随想录算法训练营第58、59天 | 739. 每日温度 496.下一个更大元素 I 503.下一个更大元素II 42. 接雨水

代码随想录系列文章目录 单调栈篇 文章目录代码随想录系列文章目录739. 每日温度496.下一个更大元素 I503.下一个更大元素II42.接雨水双指针解法dp解法单调栈解法单调栈具体的处理逻辑739. 每日温度 题目链接 暴力解法&#xff0c;双指针&#xff0c;超时, 因为数据长度是100…

【考研复试】计算机专业考研复试英语常见问题一(家庭/家乡/学校篇)

相关链接&#xff1a; 【考研复试】计算机专业考研复试英语常见问题一&#xff08;家庭/家乡/学校篇&#xff09;【考研复试】计算机专业考研复试英语常见问题二&#xff08;研究方向/前沿技术/本科毕设篇&#xff09;【考研复试】计算机专业考研复试英语常见问题三&#xff0…

Spring Boot+Vue3前后端分离实战wiki知识库系统之用户管理单点登录

用户表设计与代码生成 用户表设计 生成持久层代码 同样是在gennerator.xml中添加并执行&#xff1a; 完成用户表基本增删查改功能 首先我们应该改造controller 接着是service,service的查询条件要根据loginname来查找&#xff1a; 接着修改三个实体&#xff1a; 注…

Windows OpenGL 图像单色

目录 一.OpenGL 图像单色 1.原始图片2.效果演示 二.OpenGL 图像单色源码下载三.猜你喜欢 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录 >> OpenGL ES 基础 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录 >> OpenGL ES 特效 零基础 OpenGL ES 学习…

基于stm32单片机的电压报警系统Proteus仿真

资料编号&#xff1a;112 下面是相关功能视频演示&#xff1a; 112-基于stm32单片机的电压报警系统Proteus仿真&#xff08;源码仿真全套资料&#xff09;功能介绍&#xff1a; 采用stm32单片机的12位ADC采集电压&#xff0c;当电压值超过设置值蜂鸣器和LED产生报警&#xff…