刷题使我快乐,满脸开心.jpg

  • 来源:力扣(LeetCode)
  • 链接:https://leetcode.cn/problems/remove-duplicates-from-sorted-list-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
  • 题目数据保证链表已经按升序 排列

思路

这道题最难的地方感觉在于状态梳理
可以分别来看下

1、【状态1】now 和 now.Next 不相等

这时now 和 tail 均步进即可(tail 拼接 now 也是一样的效果)

2、【状态2】now 和 now.Next 相等

此时不能直接拼接了,而是需要持续步进now,直到找到不相等的节点

3、【状态3】跳过重复节点时,now 和 now.Next 不相等

此时虽然发现了不相等的节点,但是now所处节点是有重复的节点,还是只能步进,不能拼接。
不过此时会是一个跳出当前跳过重复节点操作的结束状态

4、【状态2】跳过重复节点后,now 和 now.Next 相等

此时其实等同于状态2,又发现了新的重复节点

5、【状态1】跳过重复节点后,now 和 now.Next 不相等

此时其实等同于状态1,都是跳过重复节点操作之外发现了一个不相等节点

6、【状态4】跳过重复节点后,now.Next 为 nil

如果不相等节点后发现链接到了终点那么其实不用做任何操作,前面都已经拼接完毕,直接返回就好

7、【状态5】跳过重复节点时,now.Next 为 nil

但是走到终点会有个特殊状态,那就是在跳过重复节点时发现到了终点,而此时的状态,tail还在指向后续的重复节点,所以需要把tail的后续直接链接到nil

或者可以把这一步当做特殊操作,在状态流转之外处理,代码中表现就是记录一个状态,循环之外再处理

至此,上代码

代码

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func deleteDuplicates(head *ListNode) *ListNode {
    if head == nil || head.Next == nil {
        return head
    }
    // 辅助记录头结点
    veryHead := &ListNode{Next: head}
    // 辅助记录当前新链表尾部节点
    tail := veryHead
    // 辅助搜索非重复节点
    now := head
    for now != nil {
        if now.Next != nil && now.Next.Val == now.Val {
            x := now.Val
            // 清理重复项,
            for now.Next != nil && now.Next.Val == x {
                now = now.Next
            }
            // 此时now位置是最后一个重复项,所以再进一步到下个非重复点再行判断
            now = now.Next
            // 清理重复直接到了末尾则额外处理下拼接
            // 或者记录个状态在退出循环后再处理也可
            if now == nil {
                tail.Next = now
            }
        } else {
            // 非重复节点,拼上
            tail.Next = now
            tail = now
            now = now.Next
        }
    }
    return veryHead.Next
}