剑指Offer:面试题18(二)——删除链表中重复的节点(java)

删除链表中重复的节点

题目描述

  • 在一个排好序的单向链表中,删除所有重复的节点
  • 例如:1->1->1->2->3->3->3->4->5->5
  • 算法删除之后变成 2->4

算法思路

  • 算法思路其实很清晰,当遇到前后两个节点相同的情况下,例如 2->3->3->3->4,找到所有的3节点,将中间的三个节点进行删除(其实就是断链再连),最终变成 2->4

  • 其中需要考虑几个点:

    • 如果是链表的前几个节点相同怎么办? 那就需要找到第一个不同的节点,作为新的头结点
    • 如果链表最后几个节点相同怎么办,这样的节点删除就需要考虑到边界判断的问题,很容易出现空指针的错误
  • 由于删除链表最经典的方法一般是需要找到前驱节点,所以在这里我们还是使用双指针进行实现

算法实现(一)

  • 这是一种比较常见的算法,就是针对不同的情况做不同的处理
  • 首先就是对链表前面几个相同节点进行删除,建立新的头结点
  • 其次就是使用双指针进行遍历,后指针来判断节点是否相同,并且寻找当前所有重复的节点
  • 这里针对链表最后节点相同的情况,temp.next != null 作为判断依据,否者会出现空指针异常
/**
 * 删除重复节点   不带头结点链表
 * 重复的节点都要被删除
 * 双指针
 * @param head
 * @return
 */
public static ListNode delDuplicationNode(ListNode head){
    if(head == null || head.next == null) return  head;
    ListNode p = head;

    //当链表前几个节点重复时,找到第一个不重复的作为头结点
    while(p.val == p.next.val){
        p = p.next;
    }
    head = p.next;


    //双指针
    p = head;
    ListNode q = head.next;
    while(q != null){
        //若后指针发现重复节点 那么就再从该位置遍历找到最后一个重复节点
        //找到最后一个重复节点之后进行断链删除
        if(q.val == q.next.val){
            ListNode temp = q.next;
            while (temp.next != null && temp.next.val == q.val){
                temp = temp.next;
            }
            p.next = temp.next;
            q = temp.next;

        }else {//如果没有重复节点就进行遍历
            p = q;
            q = q.next;
        }


    }
    return head;

}

算法实现(二)

  • 这种算法是我在查阅资料的时候发现的一种非常新颖的算法,直接上代码,应该可以看懂

  • 算法过程如下:

    • 首先判断链表头结点是否是重复,如果重复就找到新的头结点,将新的头结点再递归调用该方法
    • 如果不重复就将下一个节点作为头结点递归调用该方法
    • 也就是说一直使用判断头结点是否为重复节点的方法进行递归调用
  • 不得不说这个方法是真的很巧妙

public ListNode deleteDuplication(ListNode pHead) {
    // 若头节点为空,或者链表只有一个节点,则必没有重复,值将返回
    if(pHead == null || pHead.next == null) {
        return pHead;
    }

    // 保存头节点的下一个节点,上面已经判断了pHead.next不是空
    ListNode next = pHead.next;
    // 若头节点的值与下一个节点的值相同
    if(pHead.val == next.val) {
        do{
            // 则继续向前找出与头节点重复的节点
            // 直到找到第一个与头节点不同的节点后,退出循环
            next = next.next;
        }while(next != null && next.val == pHead.val);

        // 舍弃前面的所有重复节点,将当前第一个与头节点不同的节点作为头节点,递归调用原方法,并直接返回
        return deleteDuplication(next);
    }else {
        // 若头节点与它的下一个节点值不同,则将头节点的下一个节点作为头节点,递归调用方法
        // 并将返回值赋给头节点的next属性
        pHead.next = deleteDuplication(next);
        return pHead;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值