文章目录
- 题目链接
- 题目描述
- 解题思路
- 代码
- python
- Java
- C++
- 时空复杂度
- 华为OD算法/大厂面试高频题算法练习冲刺训练
题目链接
LeetCode82、删除排序链表中的重复节点II
题目描述
给定一个已排序的链表的头 head
, 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。
示例 1:
输入:head = [1,2,3,3,4,4,5]
输出:[1,2,5]
示例 2:
输入:head = [1,1,1,2,3]
输出:[2,3]
提示:
- 链表中节点数目在范围
[0, 300]
内 -100 <= Node.val <= 100
- 题目数据保证链表已经按升序 排列
解题思路
相比起前一题LeetCode83、删除排序链表中的重复节点,本题的区别在于要删除掉所有出现重复的节点。
即假设存在链表1->2->2->2
,那么值为1
的节点应该作为当前节点cur
,才能够顺利删除掉后面的所有值为2的节点。
同理,由于原链表的头节点可能被删除,所以本题需要设置哑节点dummyHead
指向头节点,且当前节点cur
初始化为哑节点,往后遍历
dummyHead = ListNode(0, head) # 由于头节点可能被删除,设置哑节点指向头节点
cur = dummyHead # 当前节点cur从哑节点开始
由于需要判断下下个节点和下个节点的值是否相等,因此循环迭代的while
条件为cur
的下下个节点存在,即
while(cur.next.next):
pass
若当前节点cur
的下个节点cur.next
和下下个节点cur.next.next
的值相等,则需要删除下下个节点,即
while(cur.next.next):
if cur.next.val == cur.next.next.val:
cur.next = cur.next.next
pass
由于下个节点cur.next
也是被需要删除的节点,但是还不能在现在立刻删除,因为可能后面还存在第三个、第四个等值的节点需要删除,所以可以先用一个标记del_next_flag
来标记,表示cur.next
待会儿需要被删除。
while(cur.next.next):
if cur.next.val == cur.next.next.val:
cur.next = cur.next.next
del_next_flag = True
pass
若当前节点cur
的下个节点cur.next
和下下个节点cur.next.next
的值不相等,则需要考虑del_next_flag
的值。若del_next_flag
为
True
。说明cur.next
是需要被删除的节点,删除之,且重置del_next_flag = False
False
。说明cur.next
不用被删除,cur
可以前进到cur.next
的位置。
综上整个while
循环的过程为
while(cur.next.next):
if cur.next.val == cur.next.next.val:
cur.next = cur.next.next
del_next_flag = True
else:
if del_next_flag:
cur.next = cur.next.next
del_next_flag = False
else:
cur = cur.next
注意在退出循环后,还需要再检查一次del_next_flag
的值,以判断最后的尾节点是否需要删除。即
if del_next_flag:
cur.next = cur.next.next
最后返回哑节点的下一个节点,即为所有删除操作完毕之后的链表头节点。
代码
python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is None: # 排除特殊情况
return None
dummyHead = ListNode(0, head) # 由于头节点可能被删除,设置哑节点指向头节点
cur = dummyHead # 初始化当前节点为哑节点
del_next_flag = False # bool型标记,表示下一个节点cur.next是否需要删除
while(cur.next.next): # 循环迭代所有节点
# 如果下一个节点的值等于下下个节点
if cur.next.val == cur.next.next.val:
# 删去下下个节点,将del_next_flag标记为True,用于后续删除下个节点
cur.next = cur.next.next
del_next_flag = True
else:
# 如果del_next_flag是True,说明下个节点也属于重复节点之一,需要删除
# 删除后重置del_next_flag为False
if del_next_flag:
cur.next = cur.next.next
del_next_flag = False
# 如果下个节点和下下个节点的值不等,且del_next_flag为False,
# 则cur才可以前进
else:
cur = cur.next
# 退出循环后,如果del_next_flag为True,还需要再删去尾节点
if del_next_flag:
cur.next = cur.next.next
return dummyHead.next
Java
/**
* 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; }
* }
*/
public class Solution {
public ListNode deleteDuplicates(ListNode head) {
if (head == null) {
return null;
}
ListNode dummyHead = new ListNode(0, head);
ListNode cur = dummyHead;
boolean delNextFlag = false;
while (cur.next != null && cur.next.next != null) {
if (cur.next.val == cur.next.next.val) {
cur.next = cur.next.next;
delNextFlag = true;
} else {
if (delNextFlag) {
cur.next = cur.next.next;
delNextFlag = false;
} else {
cur = cur.next;
}
}
}
if (delNextFlag) {
cur.next = cur.next.next;
}
return dummyHead.next;
}
}
C++
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
if (head == nullptr) {
return nullptr;
}
ListNode* dummyHead = new ListNode(0, head);
ListNode* cur = dummyHead;
bool delNextFlag = false;
while (cur->next != nullptr && cur->next->next != nullptr) {
if (cur->next->val == cur->next->next->val) {
cur->next = cur->next->next;
delNextFlag = true;
} else {
if (delNextFlag) {
cur->next = cur->next->next;
delNextFlag = false;
} else {
cur = cur->next;
}
}
}
if (delNextFlag) {
cur->next = cur->next->next;
}
return dummyHead->next;
}
};
时空复杂度
时间复杂度:O(N)
。仅需一次遍历链表
空间复杂度:O(1)
。
华为OD算法/大厂面试高频题算法练习冲刺训练
-
华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!
-
课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化
-
每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!
-
60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁
-
可上全网独家的欧弟OJ系统练习华子OD、大厂真题
-
可查看链接 大厂真题汇总 & OD真题汇总(持续更新)
-
绿色聊天软件戳
od1336
了解更多