五分钟玩转面试考点-数据结构-排序队列中删除重复元素(末尾重复元素-记得要删除&&直接删除)

这篇文章,细数一下遇到的链表坑...

问题1

给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。
示例 1:
输入: 1->2->3->3->4->4->5
输出: 1->2->5
示例 2:
输入: 1->1->1->2->3
输出: 2->3

小胖是怎么分析的呢?

  1. 引入一个标志位flag,一旦左右相等,那么标志为false
  2. 引入一个当前指针curNode,若是cur.val==cur.next.val那么标志设置为false。并且自旋,直至左右不相等。但是既然我引入了cur.next了,那么我需要在调用他之前非空判断!
  3. 引入新链表头指针yNode新链表当前指针newNode用于输出新链表和构建新链表。
  4. 若是标志位为true(即没有发生过自旋)那么判断头指针是不是null。重构新链表。
  5. 若标志位为false,则当前指针curNode向前移动一位。舍弃重复元素。

是什么效果呢?
打个比方:
1 1 2

  1. 初始标志位为truecur->1 以及 cur.next->1
  2. 判断cur.next!=null 并且1==1,标志位为falsecur指针一直前进。直到1!=2
  3. false新链表不处理。
  4. cur前进一位,cur->2;

继续循环...1-4

相信小伙伴们已经看出小胖的问题所在了。
(敲黑板,划重点)
(1)当结构为 1 2 2的时候,虽然我的新链表的头结点为1,但是cur.next==null的情况,并且标志位为false的情况。我并没处理。
怎么说呢?表面上看我是新创建了一个链表,在后面一直加新节点。但是我本质上是在原链表上操纵的!!!若是末尾是重复元素,新链表要指向null!!!正如此意:末尾+重复元素。而且我们在操作newNode.next元素的时候,必须要进行非空判断!!!

    if (curNode.next == null && flag == false) {  
                if (newNode != null) {  //没有加判断
                    newNode.next = null;
                }
            }

(2)第二个问题就是若是我将一个节点加入到新链表中后(头节点/尾节点),原链表的当前指针也是要前进一位的!!!即无论加入新链表成功还是失败,指针都要前进一位!!!

  //1、有序链表;2、节点A出发,若是等于本身那么就不保留
    //给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。
    public ListNode deleteDuplicates(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode newNode = null;
        ListNode yNode = null;
        ListNode curNode = head;
        while (curNode != null) {
            boolean flag = true;
            //元素A和元素A.next相同,自旋
            while (curNode.next != null && curNode.val == curNode.next.val) {
                curNode = curNode.next;
                flag = false;
            }
            //出来时候,肯定是A不等于A.next,我们要看的是是否自旋?
            if (flag) {
                if (newNode == null) {
                    newNode = yNode = curNode;  //头节点
                } else {
                    newNode.next = curNode;  //头结点新加节点
                    newNode = curNode;
                }
            }
            //是到达末尾是空,并且还是false的标志位,直接设置为null
            if (curNode.next == null && flag == false) {  //没有想到针对最后一个元素应该如何处理。
                if (newNode != null) {  //没有加判断
                    newNode.next = null;
                }
            }
            curNode = curNode.next;  //指针前进一位
            //赋予值
        }
        return yNode;
    }

问题 2(链表去重--删除重复节点)

给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例 1:
输入: 1->1->2
输出: 1->2
示例 2:
输入: 1->1->2->3->3
输出: 1->2->3


删除重复的元素?你会怎么办?
直接删除重复元素!!!

curNode.next = curNode.next.next;本质是删除节点元素。
这个不是构造新节点,从而输出,而是当前节点的值==下一个节点的值,然后删除下一个节点(链表删除操作快)。直到没有重复元素时,节点前进一步!!!

    public static ListNode deleteDuplicates(ListNode head) {
        //空元素和一个元素直接返回
        if (head == null || head.next == null) {
            return head;
        }
        ListNode curNode = head;
        //若是a=a.next,那么原指针前进一位
        while (curNode != null && curNode.next != null) {
            if (curNode.val == curNode.next.val) {
                //删除节点删除的是curNode.next
                curNode.next = curNode.next.next;
            } else
                curNode = curNode.next;
        }
        return head;
    }

问题 3 (数组去重--双指针法)

数组原地去重.png

两个指针,count是不重复元素的下标,i是原数组遍历的下标。从左到右,第一个不相等的值放于count中,重复的值直接跳过。

//数组原地去重
    public int removeDuplicates(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        //新数组的下标count
        //count里面不能含有重复元素,都不能和count相同
        //因为有序,所以只需考虑最右边的元素和原数组的关系
        int count = 0;
        for (int i = 0; i < nums.length; i++) {
            //元素相等,直接跳过,直至第一个不等的元素,
            //赋值为新数组。
            if (nums[i] != nums[count]) {
                count++;
                nums[count] = nums[i];
            }
        }
        return count + 1;  //输出新数组的长度
    }

你可能感兴趣的:(五分钟玩转面试考点-数据结构-排序队列中删除重复元素(末尾重复元素-记得要删除&&直接删除))