算法 1.7.2 删除排序链表中的重复元素 II【leetcod

2021-01-10  本文已影响0人  珺王不早朝

题目描述

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

示例 1:
  输入: 1->2->3->3->4->4->5
  输出: 1->2->5

示例 2:
  输入: 1->1->1->2->3
  输出: 2->3

数据结构

算法思维

解题要点


解题思路

一. Comprehend 理解题意
二. Choose 选择数据结构与算法
双指针解法
解题思路
  1. 声明一个新的头节点,两个指针变量,一个状态机(布尔量)
      新头节点(newHead)指向原头节点
      目标指针(target)指向新头节点
      当前指针(curr)指向原头节点的下一个节点
      状态机(hasRepeat)记录当前 target 与 curr 之间是都有重复节点
  2. 遍历整个链表
  3. 不断判断 curr.val 是否等于 target.next.val
      如果相等,将状态机置为 true
      如果不相等,判断状态机状态
        如果状态为 true 说明 curr 前为重复节点,删除重复节点,还原状态机为 false
        如果状态为 false 说明 curr 前无重复节点,目标节点 target 后移
  4. 不管任何情况,curr 都照常后移
  5. 最终需要判断 target 后的节点是否为重复的,若为重复节点则删除
边界问题
细节问题
三. Code 编码实现基本解法
class Solution {
    public ListNode deleteDuplicates(ListNode head) {

        //0.非空判断
        if (head == null) return null;

        //1.声明一个新头节点,两个指针变量,一个状态机(布尔量)
        ListNode newHead = new ListNode(-1, head); //新头节点指向原头节点
        ListNode target = newHead; //目标指针指向新头节点
        ListNode curr = head.next; //当前指针指向原头节点的下一个节点
        boolean hasRepeat = false; //记录当前 target 与 curr 之间是都有重复节点

        //2.遍历整个链表
        while (curr != null) {
            //3.不断判断当前指针节点值 是否等于 目标指针下一个节点的节点值
            if (target.next.val == curr.val) {
                //4.如果相等,将状态机置为 true
                hasRepeat = true;
            } else if (hasRepeat) { //5.如果不相等,判断状态机状态
                //6.如果状态为 true 说明 curr 前为重复节点,删除重复节点
                target.next = curr;
                hasRepeat = false; //还原状态机为 false
            } else {
                //7.如果状态为 false 说明 curr 前无重复节点,目标节点 target 后移
                target = target.next;
            }

            //8.不管任何情况,curr 都照常后移
            curr = curr.next;
        }

        //9.最终需要判断 target 后的节点是否为重复的,若为重复节点则删除
        if (hasRepeat) target.next = null;

        return newHead.next;
    }
}

执行耗时:0 ms,击败了 100.00% 的Java用户
内存消耗:37.9 MB,击败了 48.39% 的Java用户
时间复杂度:O(n) -- 链表的遍历 O(n)
空间复杂度:O(1) -- 一个新节点 O(1),两个指针的内存空间 O(1),一个布尔值的内存空间 O(1)

四. Consider 思考更优解
改变算法思维
五. Code 编码实现最优解
class Solution {

    public ListNode deleteDuplicates(ListNode head) {

        if(head==null || head.next==null) {
            return head;
        }

        ListNode dummy = new ListNode(-1);
        dummy.next = head;
        ListNode a = dummy;
        ListNode b = head;

        while(b!=null && b.next!=null) {
            //初始化的时a指向的是哑结点,所以比较逻辑应该是a的下一个节点和b的下一个节点
            if(a.next.val!=b.next.val) {
                a = a.next;
                b = b.next;
            } else {
                //如果a、b指向的节点值相等,就不断移动b,直到a、b指向的值不相等 
                while(b!=null && b.next!=null && a.next.val==b.next.val) {
                    b = b.next;
                }
                a.next = b.next;
                b = b.next;
            }
        }

        return dummy.next;
    }

}

执行耗时:1 ms,击败了 65.62% 的Java用户
内存消耗:37.8 MB,击败了 73.67% 的Java用户
时间复杂度:O(n) -- 一次链表遍历 O(n)
空间复杂度:O(1) -- 一个新节点 O(1),两个指针的内存空间 O(1) ,一个布尔值的内存空间 O(1)

六. Change 变形与延伸

=== 待续 ===

上一篇 下一篇

猜你喜欢

热点阅读