📜  数据结构|链表|问题13(1)

📅  最后修改于: 2023-12-03 15:40:01.447000             🧑  作者: Mango

数据结构 | 链表 | 问题13

此题是关于链表的操作问题,需要删除链表中重复出现的节点。

问题描述

给定一个单链表的头节点 head,请你删除其中所有重复出现的节点,只留下原始链表中没有重复出现的节点。

例如:

输入:1 -> 2 -> 3 -> 3 -> 4 -> 4 -> 5

输出:1 -> 2 -> 5

输入:1 -> 1 -> 1 -> 2 -> 3

输出:2 -> 3

数据格式

链表节点的数据类型定义如下:

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next
解法

最简单的方法就是使用一个 hashmap 来记录每个节点出现的次数,再遍历链表将出现次数大于 1 的节点删除。

这里我们介绍两种不同的解法,一种是递归,一种是迭代。

递归解法

递归解法看起来简单明了,代码也较为简短。

具体步骤如下:

  1. 如果链表为空或只有一个节点,直接返回。
  2. 判断当前节点和下一个节点的值是否相等,如果相等,删除所有这两个节点相等的节点,同时递归删除下一个节点。
  3. 如果当前节点和下一个节点的值不相等,递归删除下一个节点。

代码如下:

class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
        if not head or not head.next:
            return head
        
        if head.val == head.next.val:
            val = head.val
            while head and head.val == val:
                head = head.next
            return self.deleteDuplicates(head)
        else:
            head.next = self.deleteDuplicates(head.next)
            return head
迭代解法

迭代解法需要我们使用一些额外的指针,可以写得比较简洁。

具体步骤如下:

  1. 定义三个指针 prevcurnext,分别指向当前节点的前一个节点、当前节点和当前节点的下一个节点。
  2. 如果当前节点和下一个节点的值相等且不为空,删除所有当前节点和下一个节点值相等的节点,将当前节点的前一个节点指向当前节点的后一个节点,同时更新 curnext
  3. 如果当前节点和下一个节点的值不相等,更新指针,将 prev 指向 curcur 指向 next,再将 next 指向 next.next

代码如下:

class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
        dummy = ListNode(-1)
        dummy.next = head
        prev, cur, next = dummy, head, head
        
        while cur:
            if cur.next and cur.next.val == cur.val:
                val = cur.val
                while cur and cur.val == val:
                    cur = cur.next
                prev.next = cur
                next = cur
            else:
                prev = cur
                cur = next
                if next:
                    next = next.next
        
        return dummy.next
复杂度分析

对于两种解法的时间复杂度都是 $O(n)$,其中 $n$ 是链表的长度,因为我们每个节点只会遍历一遍,所以时间复杂度为线性。

空间复杂度上,递归解法的空间复杂度是 $O(n)$,因为我们每次递归都会使用到栈空间。而迭代解法的空间复杂度是 $O(1)$,因为我们只需要常数级别的额外空间。