zoukankan      html  css  js  c++  java
  • 删除排序链表中重复数字节点,只保留原始链表中 没有重复出现的数字(二)

    引用:原文链接:https://blog.csdn.net/dadajixxx/article/details/87551738

    /*题目
    * 在一个排序的链表中,存在着重复的节点,请删除该链表中重复的节点,重复的节点不保留,返回链表头指针
    * 示例1:1 -> 2 ->  2 ->  3 ->  3 ->  4 ->  5      -------->删除后: 1 ->  4 ->  5

    * 示例2: 1->1->1->2->3      --------->删除后:2->3

     * 

    * */

    解法1:

    原文链接:https://blog.csdn.net/if_i_were_a/article/details/89093043

     思路:与上一道题相比,这道题不同之处在于他要把所有的重复值节点都删完,前一道题的思路在于当前的值跟下一个值比较,如果重复,删除下一个,如果不重复,就继续遍历下一个元素。但是相对于这道题,当前的值即使跟下一个不相等,也有可能与之前重复过的相等。那么如何保证在这种情况下的时间复杂度为0(1)呢,可以使用一个计数器,如果有与当前节点重复的节点,删除掉重复节点之后(因为该链表是有序的,所以重复的就是当前节点的下一个),计数器的值加一。当前节点重复值删除完之后,判断当前节点是否需要删除就是判断计数器的值是否为0,如果不是0则删除该节点。然后继续遍历

    有两种特殊情况,当前节点有重复在链表的头和链表的尾。当为头的时候,因为该链表是不带表头的节点,所以有两种解法,加虚拟表头结点或者分为判断是否为为表头结点,是和不是分为两种情况。对于尾节点来说,因为出循环之后还要判断尾节点是否重复过,如果重复过,删除尾节点。

    public static ListNode deleteDuplicates1(ListNode head) {
      //添加一个虚拟的表头结点
      ListNode tempHead = new ListNode(0);
      tempHead.next = head;
      //pre之前虚拟头结点,记录元素的前一个位置,如果要删除当前元素,需要前一个位置的指针
      ListNode cur = head, pre = tempHead;
      //计数器的初始值置为0
      int count = 0;
      //当前链表为空或者遍历到链表的最后一个元素时
      while (cur != null && cur.next != null) {
        //如果当前节点和下一个结点相等,删除下一个结点,计数值加1
        if (cur.val == cur.next.val) {
          cur.next = cur.next.next;
          count++;
        } else {
          //不相等的情况下需要判断计数值是否为0来确定是否需要删除当前节点
          if (count > 0) {
            pre.next = cur.next;
            count = 0;
          } else {
            pre = cur;
          }
          cur = cur.next;
        }
      }
      //判断尾节点是否需要删除
      if (count > 0) {
        pre.next = cur.next;
      }
      //返回去除虚拟头结点的链表
      return tempHead.next;
    }
    -----------------------------------------------解法1的完整代码------start-----------------------------------------------

    原文链接:https://blog.csdn.net/if_i_were_a/article/details/89093043

    public class Num83 {
      public static void main(String[] args) {
        int[] arr = new int[]{1, 1, 1, 2, 3, 5};
        //删除链表中的重复元素,保留一个
        ListNode head = new ListNode(arr);
        head = deleteDuplicates1(head);
        System.out.println(head.toString());
      }
      public static ListNode deleteDuplicates1(ListNode head) {
        //添加一个虚拟的表头结点
        ListNode tempHead = new ListNode(0);
        tempHead.next = head;
        //pre之前虚拟头结点,记录元素的前一个位置,如果要删除当前元素,需要前一个位置的指针
        ListNode cur = head, pre = tempHead;
        //计数器的初始值置为0
        int count = 0;
        //当前链表为空或者遍历到链表的最后一个元素时
        while (cur != null && cur.next != null) {
          //如果当前节点和下一个结点相等,删除下一个结点,计数值加1
          if (cur.val == cur.next.val) {
            cur.next = cur.next.next;
            count++;
          } else {
            //不相等的情况下需要判断计数值是否为0来确定是否需要删除当前节点
            if (count > 0) {
              pre.next = cur.next;
              count = 0;
            } else {
              pre = cur;
            }
            cur = cur.next;
          }
        }
        //判断尾节点是否需要删除
        if (count > 0) {
          pre.next = cur.next;
        }
        //返回去除虚拟头结点的链表
        return tempHead.next;
      }


      static class ListNode {
        int val;
        ListNode next;

        ListNode(int x) {
        val = x;
      }

      public ListNode(int[] arr) {
        if (arr == null || arr.length == 0)
          throw new IllegalArgumentException("arr can to be empty");
        this.val = arr[0];
        ListNode cur = this;
        for (int i = 1; i < arr.length; i++) {
          cur.next = new ListNode(arr[i]);
          cur = cur.next;
        }
      }

      @Override
      public String toString() {
        StringBuilder res = new StringBuilder();
        ListNode cur = this;
        while (cur != null) {
          res.append(cur.val + "->");
          cur = cur.next;
        }
        res.append("NULL");
        return res.toString();
      }
      }
    }

    ------------------------------------------------解法1完整代码--------end------------------------------------------------

    解法2

    /*思路
    * 遍历节点的同时判断当前节点与下一个节点是否相同,如果相同则删除,
    * 删除方法 使用相同节点的前一个节点,指向相同节点的下一个节点如图
    *
    * */

    public class offer57 {

      class ListNode{
        int val;
        ListNode next=null;
        public ListNode(){ }
        public ListNode(int val){
        this.val=val;
        }
      }

    public ListNode deleteDeplication(ListNode pHead){

      if (pHead == null)  return null;

      //注意备用头结点,头结点可能被删除
      ListNode first = new ListNode(-1);

      first.next = pHead;
      ListNode p = pHead;
      //前节点
      ListNode preNode = first;

      while (p != null && p.next != null){
        if (p.val == p.next.val){ //两节点相等

          int val = p.val; //记录val用于判断后面节点是否重复
          while(p != null && p.val == val){ //这一步用于跳过相等的节点,用于删除
            p = p.next;
          }
          preNode.next = p; //删除操作,前节点的next直接等于现在的节点,把中间的节点直接跨过
        }else {
          preNode = p;
          p = p.next;
        }
      }
      return first.next;
      }
    }

    解法3:双指针法(也可以说是三指针法,设置的头结点需要参与元素链接,最后还需要输出) 设置一个新的头结点,使得链表元素进行链接和输出 当前后两个指针相同时,移动下一个指针到两个元素不相同,然后使用设置的头结点进行链接,得以越过相同元素 如果两个指针不相同,就移动处理,指针跟随

    class Solution {
      public ListNode deleteDuplicates(ListNode head) {
        if(head == null || head.next == null) return null;

        ListNode dummy = new ListNode(-1); //为链表创建一个新的头,return dummy.next 来带领整个链表
        dummy.next = head;
        ListNode current = head;
        ListNode index = dummy;

        //index在前面,所以判断index是否为null 就行

        while(current != null && current.next!= null) {

          //相等,将index移动向下一位
          if(current.val == current.next.val)  {
            while(current.next!= null && current.val == current.next.val) {current = current.next;}
            index.next = current.next;
            current = current.next;

          }  else  {

               index = current;
            current = current.next;
           }
        }
      return dummy.next;

      }

    }

    解法4:三指针法(利用三个指针和标志位flag进行处理)

    public ListNode deleteDuplicates(ListNode head) {

      ListNode pre = null;
      ListNode current = head;

      while (current != null) {
        ListNode nex = current.next; //通过while循环始终让nex作为最快的指针,注意进行null的判断
        boolean flag = false; //使用flag作为nex和cur的标志位
        while (nex != null && current.val == nex.val) {
          flag = true;
          nex = nex.next;
        }
        //对重复元素进行处理
        if (flag) {

          //判断不是刚开始,进行和nex结点的连接
          if (pre != null) { 

            pre.next = nex;

           } else { //头部

            head = nex; 

          }

          current = nex;
        } else { //对非重复元素进行连接和跳跃
          pre = current;
          current = current.next;
        }
      }

      //返回头指针
      return head;
    }

    解法5递归方法

    public static ListNode deleteDuplicates(ListNode head) {
      //baseCase
      if (head == null || head.next == null) { return head;}

      ListNode next = head.next;
      //如果是这种情况
      // 1 --> 1 --> 1 --> 2 --> 3
      // head next
      //1.则需要移动next直到出现与当前head.value不相等的情况(含null)
      //2.并且此时的head已经不能要了,因为已经head是重复的节点
      //--------------else-------------
      // 1 --> 2 --> 3
      // head next
      //3.如果没有出现1的情况,则递归返回的节点就作为head的子节点
      if (head.value == next.value) {
      //1
        while (next != null && head.value == next.value) { next = next.next; }
      //2
        head = deleteDuplicates(next);
      } else {
      //3
        head.next = deleteDuplicates(next);
      }
      return head;
      }
      }
    }

    解法6

    /**

     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) { val = x; }
     * }
     */
    class Solution {
        public ListNode deleteDuplicates(ListNode head) {
            if (head == null || head.next == null) {return head;}
     
            ListNode dummy = new ListNode(0);
            dummy.next = head;
             
            ListNode p = head;
            ListNode q = dummy;
            boolean isDel = false;
             
            while(p != null){
                if(p.next != null && p.val == p.next.val ){
                    isDel = true;
                    p.next = p.next.next;
                }else{
                    p = p.next;
                    if(isDel){
                        q.next = p;
                        isDel = false;
                    }else{
                        q = q.next;
                    }
                }
            }
            return dummy.next;
        }
    }

    解法7: 

    原文链接:https://blog.csdn.net/weixin_43573824/article/details/88603222

    解题思路:

    1. 先虚拟一个头节点,这个头节点指向给定的头节点。
    2. 如果给定的头节点的值与下一个节点的值相等,就向后遍历,找到跟当前节点值不同的节点(temp)。
    3. 将虚拟头节点的下一个节点,指向temp。
    4. 以此思路往后遍历即可。

    public static ListNode deleteDuplicates(ListNode head) {
      if (head == null || head.next == null) return head;


      ListNode dummyHead = new ListNode(-1);
      dummyHead.next = head;
      ListNode first = dummyHead;
      while (head != null && head.next != null) {
        if (head.val == head.next.val) {
          int value = head.val;
          while (head != null && head.val == value) {
            head = head.next;
          }
          first.next = head;
        }else {
          first = head;
          head = head.next;
        }
      }
      return dummyHead.next;
    }

  • 相关阅读:
    Nginx详解十四:Nginx场景实践篇之代理服务
    PyCharm设置字体风格
    PyCharm+SVN
    Nginx详解十三:Nginx场景实践篇之防盗链
    Nginx详解十二:Nginx场景实践篇之跨站访问相关
    Nginx详解十一:Nginx场景实践篇之Nginx缓存
    Nginx详解十:Nginx场景实践篇之Nginx静态资源场景配置
    Nginx详解九:Nginx基础篇之Nginx的访问控制
    浅谈控件(组件)制作方法一(附带一delphi导出数据到Excel的组件实例)(原创)
    切断数据感知控件,大大提升软件运行速度
  • 原文地址:https://www.cnblogs.com/long2050/p/12334082.html
Copyright © 2011-2022 走看看