删除排序链表中的重复元素 II(Remove-Duplicates-From-Sorted-List-II)

题干如下:

给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。
示例 1:
输入: 1->2->3->3->4->4->5
输出: 1->2->5
示例 2:
输入: 1->1->1->2->3
输出: 2->3

这题是上一篇 让我们一起啃算法—-删除排序链表中的重复元素 的进阶版。在上一篇中,我们删掉了重复的其他元素,仅保留一个元素,例如: 1 -> 2 -> 2 -> 3 变成 1 -> 2 -> 3。这题,则需要将仅保留的一个元素也删掉,例如: 1 -> 2 -> 2 -> 3 变成 1 -> 3

解题思路

借上一篇的思路,我们需要在 current 指针基础上再多准备一个前置指针 pre 和一个有效值指针 really。really 指针始终指向有效链表的尾部,pre 指针指向 current 的前置节点,因为我们需要比较当前节点 current 的值是否和前置节点、后置节点的值相等,在单向链表中,后置节点很容易获取,即 current.next,但是前置节点不能很容易获取到,需要用 pre 记录。

初始化:由于需要一个前置节点,当 current 为链表的头节点 head 时前置节点其实是不存在的,为了方便后续的逻辑,我们需要设置一个初始节点 origin,使 pre、really 指向 origin,current 指向 head。

判断 current 的 val 与 current.next 的 val 和 pre 的 val 是否相等,相等的话,则 pre 指向 current, current 指向 current.next,如果不相等,则 really.next 指向 current,really 指向 current,同时 pre 指向 current,current 指向 current.next,大致思路如上。

但是这里有个注意事项:

按照上面的逻辑,pre 指向 current 后,需要将 pre.next 置为空,例如链表为: 1 —-> 2 —-> 2,如果不把 节点1 与 节点2 的连接断开,后续返回的 origin.Next 链表结构为: 1 —-> 2 —-> 2 仔细体会一下!

流程图如下:




java json 批量key删除工具 java删除json中的一个元素_重复元素


代码实现

GO语言实现


func deleteDuplicates(head *ListNode) *ListNode {
    origin := &ListNode{Val:0}
    current := head
    pre := origin
    really := origin
    for current != nil {
        // 因为新引入了一个初始节点,防止和原始链表的第一个节点冲突,比如第一个节点刚好 Val 也为 0
        // 那么单纯 current.Val != pre.Val 判断是不够的,需要加入 pre == origin 这个判断
        if (pre == origin || current.Val != pre.Val) && (current.Next == nil || current.Val != current.Next.Val) {
            really.Next = current
            really = current

        }

        pre = current
        current = current.Next

        // 这里需要将 pre 和 current 之间的连接断开,例如链表为: 1---->2---->2,
        // 如果不把 节点1 与 节点2 的连接断开,后续返回的 origin.Next 链表结构为: 1---->2---->2 仔细体会一下!
        pre.Next = nil
    }
    return origin.Next
}


总结

每天进步一点点,加油!