删除链表中重复的节点
题目描述
- 在一个排好序的单向链表中,删除所有重复的节点
- 例如: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;
}
}