算法修炼之路——【链表】Leetcode82 删除重复节点 II

题目描述

给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中没有重复出现的数字。

示例1:

输入: head = [1, 2, 3, 3, 4, 4, 5]
输出: head = [1, 2, 5]

示例2:

输入: head = [1, 1, 1, 2, 3]
输出: head = [2, 3]

题目分析

对于此题的简单版本,参见算法修炼之路——【链表】Leetcode83 删除重复节点
我们直接考虑,这里简单来看需要找到重复数字的起始位置,直接是两个问题:

  1. 重复数字的判断问题
  2. 重复数字的定界问题

对于问题1,我们可以根据一个指针和此指针之后的节点值来判断;
对于指针,当当前数值与后一节点的数值不同时,停止遍历,此时需要联合问题2。

问题2,当我们检测到重复数字后,需要判断这个边界,即找到最后一个重复数字。此时可以将问题2看作问题1的衍生问题,这时我们需要第二个指针,此指针为临时指针,用来确定结束边界,但是停止位置为重复数字的最后一个节点,见图1:
在这里插入图片描述
图1

最简单的情况如图1所示,定界节点均在链表内部(无边界问题),此时直接将currP.next指向tmpP.next即可,这里需要特殊考虑两种情况:

  1. head值即为重复数值时,图1中的currP则会打破我们的设定(currP在重复数字的前一个节点),这个时候需要借助哨兵机制,进行统一规则:
    在这里插入图片描述
  2. 当重复数字在链表尾部出现时,来检验我们的统一规则是否适用:
    在这里插入图片描述
    此时可以看到,当链表末尾出现重复数字后,我们假设的规则依然适用,则截止到这里,我们的想法已经在通常情况、首部边界情况和尾部边界情况均进行了测试与适配,剩下就是进行编码调试。

步骤罗列

  1. 初始化我们需要的指针和哨兵:dummyHead = new ListNode(-1); currP = dummyHead;
  2. 判断currP.next的数值和currP.next.next是否为空,和数值是否相等;直至这些条件同时不满足,令currP.next = tmpP.next;
    1. 检测 重复数字
    2. 寻找最后一个重复数字
    3. 删除重复部分
  3. 返回dummyHead.next;

解题代码

    public static ListNode solutionWithTwoP(ListNode head){
        if(head == null || head.next == null) return head;
        
        //1. init pointers and dummyHead
        ListNode dummyHead = new ListNode(-1);
        dummyHead.next = head;
        ListNode currP = dummyHead;
        
        while(currP.next != null && currP.next.next != null){
            //1. detected repeat node
            if(currP.next.val == currP.next.next.val){
                ListNode tmpP = currP.next;
                
                //2. found the last repeated node
                while(tmpP != null && tmpP.next != null 
                        && tmpP.val == tmpP.next.val)
                    tmpP = tmpP.next;
                //3. delete repeated node
                currP.next = tmpP.next;
                
            }else{
                currP = currP.next;
            }
            
        }
        
        return dummyHead.next;
    }

复杂度分析

时间复杂度:我们对链表仅进行了一次遍历,故时间复杂度为0(n);
空间复杂度:没有辅助容器,故为O(1);

GitHub代码

完整可运行代码参见GitHub

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值