【Py/Java/C++三种语言详解】LeetCode每日一题240115【链表】LeetCode82、删除排序链表中的重复节点II

题目链接

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了解更多

  • 22
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值