zoukankan      html  css  js  c++  java
  • 如何删除链表中值重复的节点

    前言

      最近在刷《剑指offer》的题,其中有一道题目叫做删除链表中重复的节点,我想了半天没想到比较好的解决办法,于是看了看大佬的解析(菜哭了)。不看不知道,一看吓一跳,这尼玛写的也太妙了,忍不住写篇博客记录一下这个解题思路和代码。


    题目描述

      在一个排好序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5


    解题思路

      这道题我们分两种情况来考虑:

    1. 首先第一种情况:头节点的值存在重复;比如1->1->1->2->3->3->4,前面这个链表的头节点重复了3次,所以这时候,我们应该舍弃前3个重复的节点1,将2作为新的头节点,再继续向后判断;
    2. 第二种情况就是头节点并不与它的下一个节点重复;比如上面的这个链表,我们去除了前面的3个1之后,剩下2->3->3->4,这时候,头节点不与后面的节点重复了,那我们保留头节点,并继续向后判断,发现后面后面的两个3发生了重复,于是,我们去除这个两个节点,并让原来头节点的next指向去除重复后的下一个位置,也就变成了2->4;若4后面还有其他重复,则我们去除重复后,让4指向剩下的部分;

    代码实现

      其实上面的思路并不是很难想到,关键是代码如何实现呢?下面这个代码就是大佬对于上面这个思路的实现:

    public ListNode deleteDuplication(ListNode pHead) {
        // 若头节点为空,或者链表只有一个节点,则必没有重复,值将返回
        if(pHead == null || pHead.next == null) {
            return pHead;
        }
    
        // 保存头节点的下一个节点,上面已经判断了pHead.next不是空
        ListNode next = pHead.next;
        // 若头节点的值与下一个节点的值相同
        if(pHead.val == next.val) {
            do{
                // 则继续向前找出与头节点重复的节点
                // 直到找到第一个与头节点不同的节点后,退出循环
                next = next.next;
            }while(next != null && next.val == pHead.val);
    
            // 舍弃前面的所有重复节点,将当前第一个与头节点不同的节点作为头节点,递归调用原方法,并直接返回
            return deleteDuplication(next);
        }else {
            // 若头节点与它的下一个节点值不同,则将头节点的下一个节点作为头节点,递归调用方法
            // 并将返回值赋给头节点的next属性
            pHead.next = deleteDuplication(next);
            return pHead;
        }
    }
    
    // 以下是节点ListNode
    class ListNode {
    	int val;
    	ListNode next = null;
    
    	ListNode(int val) {
    		this.val = val;
    	}
    }
    

      上面的代码我加了点注释,看得难受可以复制到编辑器中,删掉注释再看。

      上面这段代码,给我的感觉就是把递归用的出神入化(可能是我太菜了)。除去注释,短短几行代码,就将上面的思路完全实现,下面我来解读一下:

      上面的代码首先做了特判,若传入的头节点是空,或者没有后续节点,那就不用去重,直接返回。这之后,先将头节点的下一个节点保存。

      我们先判断当前是否满足前面说的第一种情况:头节点发生了重复,若发生了这种情况,就一直向后找,直到找到第一个不与头节点重复的节点,然后我们舍弃前面的节点,把这个节点当作头节点,递归调用方法,并直接将返回值返回,这相当于是把后面剩下的部分当作一条新的链表,而前面重复的就直接舍弃了;

      若当前链表是我们之前说的第二种情况:头节点不重复,则我们将头节点的下一个节点作为参数,递归调用原方法,将除去头节点后的子链表看作是一个新链表,而方法返回值就是这个子链表去重后的链表,我们将其与原来头节点关联,就完整地去重了。

      上面代码最精妙的地方就是递归,将原链表中除去头节点的剩余部分,当作一个新链表进行处理,短短几行代码,就实现了去重。

  • 相关阅读:
    Java实现 蓝桥杯VIP 算法训练 黑色星期五
    Java实现 蓝桥杯VIP 算法训练 比赛安排
    Java实现 蓝桥杯VIP 算法训练 比赛安排
    Java实现 蓝桥杯VIP 算法训练 斜率计算
    Java实现 蓝桥杯VIP 算法训练 斜率计算
    Java实现 蓝桥杯VIP 算法训练 整数平均值
    Java实现 蓝桥杯VIP 算法训练 整数平均值
    控件动态产生器(使用RegisterClasses提前进行注册)
    Delphi编写自定义控件以及接口的使用(做了一个TpgDbEdit)
    Log4delphi使用心得
  • 原文地址:https://www.cnblogs.com/tuyang1129/p/12177777.html
Copyright © 2011-2022 走看看