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;
    	}
    }
    

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

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

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

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

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

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

  • 相关阅读:
    Jenkins操作手册 巨详细,一篇足矣!
    获取外网的IP的方法!
    Winson.Framework 2.0 搭建FLASH视频教程!
    JS读写COOKIE的方法!
    Winson.Framework 2.0发布!
    第一次自己做的电子杂志--《深博网志》!
    ProMesh.Net基本使用说明!
    ExtJS学习心得(三)
    安装SQL2000时,最后报安装配置服务失败的解决!
    ExtJS学习心得(二)
  • 原文地址:https://www.cnblogs.com/tuyang1129/p/12177777.html
Copyright © 2011-2022 走看看