必须拿起的最小连续卡牌数

标签: 数组 哈希表 滑动窗口

难度: Medium

给你一个整数数组 cards ,其中 cards[i] 表示第 i 张卡牌的 。如果两张卡牌的值相同,则认为这一对卡牌 匹配

返回你必须拿起的最小连续卡牌数,以使在拿起的卡牌中有一对匹配的卡牌。如果无法得到一对匹配的卡牌,返回 -1

示例 1:

输入:cards = [3,4,2,3,4,7]
输出:4
解释:拿起卡牌 [3,4,2,3] 将会包含一对值为 3 的匹配卡牌。注意,拿起 [4,2,3,4] 也是最优方案。

示例 2:

输入:cards = [1,0,5,3]
输出:-1
解释:无法找出含一对匹配卡牌的一组连续卡牌。

提示:

  • 1 <= cards.length <= 105
  • 0 <= cards[i] <= 106

Submission

运行时间: 107 ms

内存: 35.6 MB

class Solution:
    def minimumCardPickup(self, cards: List[int]) -> int:
        # 字典用于记录最近一次卡牌值的索引
        d = dict()
        ans = len(cards)+1
        for i, item in enumerate(cards):
            if (item in d):
                ans = min(ans, i - d[item] + 1)
            d[item] = i 
        return -1 if ans == len(cards)+1 else ans
      
        '''
        cardsSet = set(cards)
        if len(cards) == len(cardsSet):
            return -1

        # create a dictionary to store location of every elements
        index = {}
        for i in range(len(cards)):
            if cards[i] not in index:
                index[cards[i]] = []
            index[cards[i]].append(i)
        
        miniLen = len(cards)
        for key in index:
            if len(index[key]) > 2:
                lastLoc = index[key][0]
                for i in index[key][1:-1]:
                    currLoc = i
                    currLen = currLoc - lastLoc
                    lastLoc = i
                    miniLen = min(currLen, miniLen)
            elif len(index[key]) == 2 :
                currLen = index[key][1] - index[key][0]
                miniLen = min(currLen, miniLen)
            elif len(index[key]) < 2:
                continue
        
        return miniLen+1
        '''

Explain

此题解使用了哈希表来存储每个卡牌值最近一次出现的索引。遍历卡牌数组,对于每张卡牌,如果它之前出现过(即在哈希表中存在),则计算当前索引与上一次出现索引的差(即连续卡牌的数量),并更新最小数量。如果没有找到任何匹配的卡牌对,则返回-1。这种方法直接通过索引差计算得到最小连续卡牌数,避免了不必要的重复计算。

时间复杂度: O(n)

空间复杂度: O(n)

class Solution:
    def minimumCardPickup(self, cards: List[int]) -> int:
        # Initialize a dictionary to store the latest index of each card value
        d = dict()
        # Initialize the minimum number of cards to a large value
        ans = len(cards)+1
        # Iterate over the card list
        for i, item in enumerate(cards):
            # If the card value has been seen before, calculate the distance
            if (item in d):
                ans = min(ans, i - d[item] + 1)
            # Update the dictionary with the current index for the card value
            d[item] = i
        # Return -1 if no such pair is found, else return the minimum distance
        return -1 if ans == len(cards)+1 else ans

Explore

在此问题中,存储卡牌值的最新索引是为了直接计算两次相同卡牌出现的连续距离,这是求解最小连续卡牌数的关键。存储出现次数或其他信息不能直接提供两次出现之间的距离,因此不适用于解决此特定问题。

使用`ans = len(cards)+1`初始化最小卡牌数的目的是确保在比较过程中,任何有效的连续卡牌数都小于这个初始值。这样可以保证即使数组中的所有卡牌都不重复,也能正确地返回一个超过任何可能卡牌数的值,从而通过后续的条件判断返回-1,表明没有找到任何连续的卡牌对。

返回-1作为错误或特殊情况的标志是一种常见的编程惯例,有助于调用者区分正常结果和没有找到匹配的特殊情况。这种设计提高了算法的可读性和易用性,使得算法的输出更加直观明确,便于外部代码根据返回值做出适当的处理。

是的,这种方法考虑了所有可能的边界条件。每当遇到重复的卡牌时,通过计算当前索引与上一次出现索引的差值来更新最小连续卡牌数,这包括了数组中只有一对匹配卡牌的情况。此外,初始化`ans`为一个大于任何可能卡牌长度的值也保证了即使数组中没有重复卡牌,算法仍然能正确返回-1。