「这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战」
前言
力扣第八十二题 删除排序链表中的重复元素 II 如下所示:
存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除链表中所有存在数字重复情况的节点,只保留原始链表中 没有重复出现 的数字。
返回同样按升序排列的结果链表。
示例 1:
输入: head = [1,2,3,3,4,4,5]
输出: [1,2,5]
示例 2:
输入: head = [1,1,1,2,3]
输出: [2,3]
一、思路
题目意思很简单就是删除链表中的重复项,且需要保留原始列表
因为题目中规定了需要保留原始链表,所以是不可以再新建一个链表来逐个添加不重复节点的。
找到链表中的重复项是一件比较容易的事情,找到重复项肯定是有一个指针 current 指向当前节点,另一个指针 next 指向下一个节点,只要这两个节点的值相等就说明重复了,然后一直 next 节点向下,直到出现不重复的值,如下图所示:
我们发现这个时候没办法让 current 的上一个节点的下一个元素指向 next!
所以我们就需要一个前置节点 before 了,它始终指向 current 的上一个元素,详细步骤见下面的图解
图解算法(增加前置节点)
此处以实力中的 head = [1,2,3,3,4,4,5] 作为例子
- 我们先新增一个
before节点,如下图所示:
- 因为
current和next指向的元素1和2互不相等,故都指向自身的下一个元素
- 因为
current和next指向的元素2和3互不相等,故继续指向自身的下一个元素
- 此时
current和next指向的元素相等,此时next需一直向下找到与current不相等的元素,如下图所示:
- 删除重复元素
此时 before 节点的作用就体现出来了,我们只需将 before.next = next,current = next , next = next.next 即可,如下图所示:
- 删除后续重复元素的步骤同上,就不过多赘述了。
二、实现
实现代码
在实现代码中为了简洁性,使用 before.next 代替了 current
/**
* 删除重复项
* @param head
* @return
*/
public ListNode deleteDuplicates(ListNode head) {
// 特殊情况
if (head == null || head.next == null) {
return head;
}
ListNode before = new ListNode(-1, head); // 前置节点
ListNode newHead = before;
ListNode next = head.next;
while (next != null) {
if (next.val == newHead.next.val) {
// 只要与当前值相等,就一直向下
while (next != null && next.val == newHead.next.val) {
next = next.next;
}
// 删除该节点,和之前的节点
newHead.next = next;
if (next == null) { // 如果后面没有元素了
break;
}
next = next.next;
} else {
newHead = newHead.next;
next = next.next;
}
}
return before.next;
}
测试代码
public static void main(String[] args) {
ListNode listNode1 = new ListNode(1, new ListNode(1, new ListNode(1, new ListNode(2, new ListNode(3)))));
ListNode listNode2 = new ListNode(1, new ListNode(2, new ListNode(3, new ListNode(3, new ListNode(4, new ListNode(4, new ListNode(5)))))));
ListNode listNode3 = new ListNode(1, new ListNode(1));
new Number82().deleteDuplicates(listNode3);
}
结果
三、总结
感谢看到最后,非常荣幸能够帮助到你~♥
如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~