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

题目描述

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

示例1:

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

示例2:

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

解题思路

我们可以简单分析,当可使用辅助容器的时候,可以存在一个游历指针和一个辅助链表,指针游历链表并与辅助链表尾进行对比,若大于其值则将其插入辅助链表尾部,否则继续下一个节点。

步骤罗列

  1. 初始化一个指针p,一个辅助链表dummyHead,一个指向辅助链表尾部的指针tailP;
  2. p指向head, dummyHead初始化为null;
  3. p遍历,并与tailP比较值是否相等:相等时 p继续;否则插入tailPtailP更新自己。

解题代码1

    public static ListNode solutionWithCon(ListNode head){
        /*
        Time Com: O(n)
        Space Com: O(m) (m:length of output linkedlist)
        */
        if(head == null || head.next == null) return head;
        
        //1. init pointers and container
        ListNode p = head;
        ListNode dummyHead = new ListNode(-1);
        ListNode tailP = null;
        
        //2. go through linkedlist
        while(p != null){
            
            if(tailP != null){ 
                // 3. seek next node
                if(p.val > tailP.val){
                    tailP.next = new ListNode(p.val);
                    tailP = tailP.next;
                } 
            }else if(dummyHead.next == null){ // very first iteration                
                tailP = new ListNode(p.val);
                dummyHead.next = tailP;
            }
            p = p.next;
        }
        
        return dummyHead.next;
    }

复杂度分析

时间复杂度为:O(n)
空间复杂度:O(m) m为输出链表的长度

进阶1

可否有空间复杂度为O(1)的解题方法,这里我们惯性思维会考虑到双指针,这里设置slowP为输出链表的尾节点,即在此节点之前均为排序后的且均无重复节点的序列;fastP去遍历slowP之后的节点,当fastP到达整个链表尾部时,则结束遍历,此时令slowP的下一节点为null.

步骤罗列

  1. 初始化两个指针slowPfastP均指向, slowP指向head, fastP指向head.next;
  2. fastP大于slowP值时,进行值的交换;
  3. fastP == null为循环终止条件;
  4. slowP.next = null, 返回head;

解题代码2

    public static ListNode solutionWithTwoP(ListNode head) {
        /*
        Time Com: O(n)
        Space Com: O(1) 
         */
        if (head == null || head.next == null) {
            return head;
        }

        //1. init pointers and container
        ListNode slowP = head;
        ListNode fastP = head.next;

        //2. go through linkedlist
        while (fastP != null) {

            if (fastP.val > slowP.val) 
            {
                // 3. found next node and exchange value
                if (slowP.next != fastP)
                    slowP.next.val = fastP.val;
                
                slowP = slowP.next;
            }

            fastP = fastP.next;
        }
        //4. release un-useful tail behind slowP
        slowP.next = null;
        return head;
    }

复杂度分析

时间复杂度:对数据的遍历为一遍,认为O(n)
(严格的来说为O(m+n),n为输入链表长度,m为输出链表长度)

空间复杂度:O(1),不需要额外容器辅助;

进阶2

我们能否通过一个指针完成任务??在solutionWithTwoP代码中我们能否再进一步的精简代码,因为题干为已排序后的链表。

解题思路

我们依旧将slowP作为输出链表的节点,对于遍历的另外一个依托,不是第二个指针,而是移动整个链表(时刻更新slowP.next

步骤罗列

  1. 创建并初始化slowP=head;
  2. 比较slowPslowP.next
  3. slowP.next == null为循环终止条件;

解题代码3

    public static ListNode solutionWithP(ListNode head) {
        /*
        Time Com: O(n)
        Space Com: O(1) 
         */
        if (head == null || head.next == null) {
            return head;
        }

        //1. init pointers and container
        ListNode slowP = head;

        //2. go through linkedlist
        while (slowP.next != null && slowP.next.next != null) {
            
            // 3. found next node and re-order node
            if (slowP.next.val > slowP.val)             
                slowP = slowP.next;                
            
            slowP.next = slowP.next.next;    
        }
        return head;
    }

复杂度分析

时间复杂度:这里仅遍历了一次数据,故为O(n);
空间复杂度:不需要额外辅助容器,故为O(1);

GitHub代码

完整可运行代码文件请点击GitHub

发布了47 篇原创文章 · 获赞 55 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/u011106767/article/details/105237642
今日推荐