【面试系列】集度汽车-二面算法

集度汽车一面算法:链表删除倒数第N个元素(要求时间复杂度是O(n))

集度汽车二面算法:

        1 删除排序链表中的重复元素(只保留一个重复元素的值)

         2 删除排序链表中的重复元素(全部删除)

思路:

        这两个题大体类似,考的都是链表的增删,需要注意的点:

        1 边界问题

        2 删除元素的方式

第一个算法题:

        解法一:双指针

   public ListNode deleteDuplicates(ListNode head) {
      //定义第一次遍历元素的指针1
      ListNode currentNode = head;

      while(currentNode != null) {
         //定义第二次遍历重复元素的指针2
         ListNode nextNode = currentNode.next;

         //当指针1和2的值相等的时候,指针2继续向后遍历,直到元素为null或者val不相等为止
         while(nextNode != null && currentNode.val == nextNode.val) {
            nextNode = nextNode.next;
         }

         //指针1指向不相等的元素,也就是指针2(相当于删除中间重复元素)
         currentNode.next = nextNode;
         
         //指针1指向指针2的原始位置,继续遍历
         currentNode = nextNode;
      }

      return head;
   }

解法二:递归

   public ListNode deleteDuplicates2(ListNode head) {
      //递归的终止条件之一(当前元素为空或者当前元素的next为空)
      if(head == null || head.next == null){
         return head;
      }

      //递归判断,当前节点的next节点
      head.next = deleteDuplicates2(head.next);

      //如果当前节点的val等于当前节点next节点的val,那么返回next作为递归的结果
      if(head.val == head.next.val){
         head = head.next;
      }

      return head;
   }

第二道算法题:

        第二道题是第一道题的变型,如果使用双指针,需要记录被删除元素的前一个节点

       

        解法一:双指针1.0

   //解法1 指针
   public static ListNode deleteDuplicates1(ListNode head) {
      ListNode preNode = new ListNode(0);
      preNode.next = head;

      //重新定义头结点(因为原始的头结点有可能变动)
      ListNode newHead = null;

      while(preNode.next != null){
         //标示位: 判断有没有重复节点的删除
         Boolean flag = false;
         ListNode nextNode = preNode.next.next;

         while(nextNode != null && preNode.next.val == nextNode.val){
            flag = true;
            nextNode = nextNode.next;
         }

         //如果有节点的删除,前指针直接越过重复元素,指向重复元素的后一个
         if(flag){
            preNode.next = nextNode;
         }
         //如果节点没有删除,前指针指向当前节点
         else{
            //判断最新头结点是否存在,如果不存在,创建新的头结点
            //此时注意边界: 需要先与代码6 判断newHead == null, 因为如果后判断,preNode就已经移动到了preNode.next
            if(newHead == null){
               newHead = preNode.next;
            }

            //6
            preNode = preNode.next;
         }
      }

      return newHead;
   }

 解法二:官方版本(通过定义哑节点)

   public static ListNode deleteDuplicates2(ListNode head) {
      if(head == null) {
         return head;
      }

      ListNode dummyNode = new ListNode(0,head);
      
      //定义哑结点作为头部节点的前一个节点
      ListNode currentNode = dummyNode;

      while(currentNode.next != null && currentNode.next.next != null){
         if(currentNode.next.val == currentNode.next.next.val){
            //记录重复元素的值
            int x = currentNode.next.val;

            //删除重复元素
            while(currentNode.next != null && currentNode.next.val == x){
               currentNode.next = currentNode.next.next;
            }
         }else{
            currentNode = currentNode.next;
         }
      }

      return dummyNode.next;
   }

解法三:递归版本


   public static ListNode deleteDuplicates3(ListNode head) {
      //没有节点或者只有一个节点,必然没有重复元素
      if(head == null || head.next == null) {
         return head;
      }

      // 当前节点与下一个节点的值重复了,重复的值都不能要。
      // 一直往下找,找到不重复的节点。返回对不重复节点的递归结果
      if(head.val == head.next.val) {
         ListNode notDupNode = head.next.next;

         while(notDupNode != null && notDupNode.val == head.val) {
            notDupNode = notDupNode.next;
         }

         return deleteDuplicates3(notDupNode);
      }
      // 当前节点和下一个节点,值不同,则head的值是需要保留的,对head.next继续递归
      else {
         head.next = deleteDuplicates3(head.next);

         return head;
      }
   }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值