链表组件

标签: 数组 哈希表 链表

难度: Medium

给定链表头结点 head,该链表上的每个结点都有一个 唯一的整型值 。同时给定列表 nums,该列表是上述链表中整型值的一个子集。

返回列表 nums 中组件的个数,这里对组件的定义为:链表中一段最长连续结点的值(该值必须在列表 nums 中)构成的集合。

示例 1:

输入: head = [0,1,2,3], nums = [0,1,3]
输出: 2
解释: 链表中,0 和 1 是相连接的,且 nums 中不包含 2,所以 [0, 1] 是 nums 的一个组件,同理 [3] 也是一个组件,故返回 2。

示例 2:

 

输入: head = [0,1,2,3,4], nums = [0,3,1,4]
输出: 2
解释: 链表中,0 和 1 是相连接的,3 和 4 是相连接的,所以 [0, 1] 和 [3, 4] 是两个组件,故返回 2。

提示:

  • 链表中节点数为n
  • 1 <= n <= 104
  • 0 <= Node.val < n
  • Node.val 中所有值 不同
  • 1 <= nums.length <= n
  • 0 <= nums[i] < n
  • nums 中所有值 不同

Submission

运行时间: 88 ms

内存: 19.2 MB

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def numComponents(self, head: ListNode, G: List[int]) -> int:
        g = set(G)
        ret = 0
        cur = head
        while cur:
            if cur.val in g and (cur.next is None or cur.next.val not in g):
                ret += 1
            cur = cur.next
        return ret
        

Explain

题解的思路是通过将nums列表转化为集合g,利用集合的快速查找特性来判断链表中的值是否属于nums。遍历链表,如果当前节点的值在集合g中,且下一个节点不存在或下一个节点的值不在集合g中,那么认为找到了一个组件。这样可以确保连续且仅属于nums的节点序列被准确计数。

时间复杂度: O(n)

空间复杂度: O(m)

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def numComponents(self, head: ListNode, G: List[int]) -> int:
        g = set(G)  # 将列表G转换为集合g,以便快速查找
        ret = 0  # 初始化组件计数器
        cur = head  # 初始化当前节点为头结点
        while cur:  # 遍历链表直到cur为空
            if cur.val in g and (cur.next is None or cur.next.val not in g):  # 如果当前节点值在g中,并且下一节点不存在或值不在g中
                ret += 1  # 找到一个组件,计数器加一
            cur = cur.next  # 移动到下一节点
        return ret  # 返回总组件数
        

Explore

在Python中,集合(set)的主要优势在于其基于哈希表的实现,这使得平均情况下元素查找的时间复杂度为O(1)。相比之下,列表(list)的元素查找是通过线性搜索,其时间复杂度为O(n)。因此,当需要频繁检查元素是否存在于某个数据结构中时,使用集合可以大幅提高效率。在本题中,将nums转换为集合可以显著加快链表节点值的查找速度,尤其是当nums较大时更为明显。

在这个算法中,一个组件被定义为链表中连续的节点序列,这些节点的值都属于集合g。为了确定一个组件的结束,我们不仅需要确认当前节点的值在集合g中,还需确保这一连续序列到此结束。这可以通过两种情况来检测:1) 当前节点的下一个节点不存在,意味着已到链表末尾;2) 下一个节点的值不在集合g中,意味着连续序列被中断。只有在这两种情况之一发生时,我们才能确定一个完整的组件已经结束,因此需要进行这样的双重检查。

是的,如果链表中所有节点的值都存在于nums中,这种算法仍然能正确计算组件的数量。在这种特殊情况下,整个链表本身就是一个连续的组件,因为从链表的开始到结束,所有节点的值都属于集合g,且没有被任何不属于g的节点值中断。根据算法逻辑,只要遍历到链表的最后一个节点,它会被正确地计为一个组件。

该算法在处理链表只有一个节点的情况时,其输出也是正确的。如果这个单一的节点的值存在于集合g中,根据算法逻辑,由于没有下一个节点,这个节点将被视为一个完整的组件,并且计数器会增加1。如果节点的值不在集合g中,则不会增加计数器。因此,无论节点的值是否在集合g中,算法都能正确处理只有一个节点的链表情况。