与一般去重不同的点 在于 若出现数值重复的节点 则所有该数值的节点都删除
一般的去重是“重复值仅保留一份” 所以遍历时只需循环判断当前节点与下一个节点的数值是否重复 是则将当前节点的next
指向下下个节点 起到移除下一个节点的作用 if (cur.val == cur.next.val) cur.next = cur.next.next;
即【1,2,2,3,4,4,4】转为【1,2,3,4】
现在要将所有重复节点都删除 可以先遍历链表 将有重复的数字记录到数组或哈希表中 第二次遍历链表删除有重复的节点 即【1,2,2,3,4,4,4】 第一次遍历记录下【2,4】 第二次遍历移除val
已被记录的节点变为【1,3】
贴上代码 空间复杂度$O(n)$
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode deleteDuplicates(ListNode head) {
if (head == null) return head;
head = new ListNode(101, head);
// 记录数字i是否重复 i=val+100 -100<=val<=100 加上偏移变为0<=i<=200
boolean[] vis = new boolean[210];
ListNode cur = head.next;
while (cur.next != null) {
if (cur.val == cur.next.val) vis[cur.val + 100] = true; // 与下个节点重复
cur = cur.next;
}
cur = head;
while (cur.next != null) {
if (vis[cur.next.val + 100]) cur.next = cur.next.next; // 下个节点属于重复节点 则移除下个节点
else cur = cur.next; // 否则cur后移
}
return head.next;
}
}
但我们完全可以在一次遍历的时候 把重复的节点一同删掉
如果cur
的下个节点与下下个节点重复,记录下重复节点的值,反复移除cur
的下个节点 将cur
的next
指向该节点的下一位 直到节点不再重复或到达数组末尾
谢大佬@itdef评论提醒 写的时候不够严谨 注意上面的逻辑 有个前提 cur
本身不能是重复节点 因为移除操作只作用在后续的节点 如果cur
就是重复的 那么最后会被保留
下面代码里
cur
是从事先创建的虚拟表头开始向后遍历的 而这个表头不计入最后返回的链表 return head.next;
(所以保证了cur
初始就不是重复节点)
所以在一开始 cur
的下个节点就是原链表的第一个节点 程序会先把cur
后面的重复节点都移除 再把cur
后移 (这保证了cur
后续也不会是重复节点)
因为判断发生在cur
的后两位 所以要注意cur.next
和cur.next.next
是否为空的情况
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode deleteDuplicates(ListNode head) {
if (head == null) return head;
head = new ListNode(-201, head);
ListNode cur = head;
while (cur.next != null && cur.next.next != null) {
if (cur.next.val == cur.next.next.val) { // 下个节点与下下个节点重复
int x = cur.next.val; // 记录下重复值
while (cur.next != null && cur.next.val == x) // 反复移除下个节点直到末尾或不再重复
cur.next = cur.next.next;
} else {
cur = cur.next; // 如果不重复 cur可直接后移
}
}
return head.next;
}
}
如果cur的下个节点与下下个节点重复,这个前提是cur不与这些节点重复吧?
如果cur也是重复节点之一呢?
我这是被大佬翻牌子了么 这该死的激动
已补充 谢谢谢
共同学习进步