按递增顺序显示卡牌

标签: 队列 数组 排序 模拟

难度: Medium

牌组中的每张卡牌都对应有一个唯一的整数。你可以按你想要的顺序对这套卡片进行排序。

最初,这些卡牌在牌组里是正面朝下的(即,未显示状态)。

现在,重复执行以下步骤,直到显示所有卡牌为止:

  1. 从牌组顶部抽一张牌,显示它,然后将其从牌组中移出。
  2. 如果牌组中仍有牌,则将下一张处于牌组顶部的牌放在牌组的底部。
  3. 如果仍有未显示的牌,那么返回步骤 1。否则,停止行动。

返回能以递增顺序显示卡牌的牌组顺序。

答案中的第一张牌被认为处于牌堆顶部。

示例:

输入:[17,13,11,2,3,5,7]
输出:[2,13,3,11,5,17,7]
解释:
我们得到的牌组顺序为 [17,13,11,2,3,5,7](这个顺序不重要),然后将其重新排序。
重新排序后,牌组以 [2,13,3,11,5,17,7] 开始,其中 2 位于牌组的顶部。
我们显示 2,然后将 13 移到底部。牌组现在是 [3,11,5,17,7,13]。
我们显示 3,并将 11 移到底部。牌组现在是 [5,17,7,13,11]。
我们显示 5,然后将 17 移到底部。牌组现在是 [7,13,11,17]。
我们显示 7,并将 13 移到底部。牌组现在是 [11,17,13]。
我们显示 11,然后将 17 移到底部。牌组现在是 [13,17]。
我们展示 13,然后将 17 移到底部。牌组现在是 [17]。
我们显示 17。
由于所有卡片都是按递增顺序排列显示的,所以答案是正确的。

提示:

  1. 1 <= A.length <= 1000
  2. 1 <= A[i] <= 10^6
  3. 对于所有的 i != jA[i] != A[j]

Submission

运行时间: 27 ms

内存: 16.2 MB

class Solution:
    def deckRevealedIncreasing(self,nums: List[int]) -> List[int]:
        n=len(nums)
        nums.sort()
        ans=[0]*n
        d=deque(range(n))
        for v in nums:
            ans[d.popleft()]=v
            if d:
                d.append(d.popleft())
        return ans

Explain

这个题解的核心思想是模拟牌组的重排过程,但是反向操作。首先对数组进行排序,确保最终的顺序是递增的。然后使用一个双端队列(deque)来模拟牌组的索引。队列的每个元素代表牌组中卡牌的位置,初始状态是0到n-1的顺序。对于排序后的数组,我们按顺序取出每个元素:1) 将队列的前端元素(当前顶部的卡牌位置)弹出并填充到结果数组的相应位置;2) 如果队列还有元素,则将队列的新前端元素(下一个顶部的卡牌位置)移动到队列的尾部,模拟将牌放到底部的动作。重复这个过程直到所有的卡牌都被处理过。

时间复杂度: O(n log n)

空间复杂度: O(n)

class Solution:
    def deckRevealedIncreasing(self, nums: List[int]) -> List[int]:
        n = len(nums)  # 获取牌的数量
        nums.sort()  # 对卡牌排序以确保最终展示顺序为递增
        ans = [0] * n  # 初始化结果数组
        d = deque(range(n))  # 使用deque模拟卡牌的索引
        for v in nums:  # 遍历排序后的卡牌值
            ans[d.popleft()] = v  # 将当前最小的卡牌放到正确的位置
            if d:  # 如果还有卡牌在队列中
                d.append(d.popleft())  # 模拟将下一张卡牌放到牌组底部的操作
        return ans  # 返回最终的牌组顺序

Explore

双端队列(deque)在这个算法中的主要作用是模拟和管理牌的索引,以便按照题目要求的顺序来重新排列卡牌。通过使用双端队列,算法可以轻松地从两端添加或删除元素。在这个特定的算法中,deque允许我们有效地从队列前端移除元素,用于确定当前卡牌的位置,并且可以将元素从前端移除后再添加到尾端,这模拟了将牌放到堆的底部的操作。这种操作是必要的,因为题目要求按照特定方式展示卡牌,而双端队列提供了实现这一逻辑的简洁方法。

将队列的新前端元素移动到队列的尾部的操作模拟了现实中将牌的顶部卡牌放到牌堆底部的动作。在题目的牌组重排过程中,每次展示一张牌后,下一张位于顶部的牌被放到底部,这样可以确保下次抽取牌时,顶部的牌是正确的。这个操作是重现题目要求的卡牌展示顺序的关键步骤,确保每次揭示的顺序符合题目要求的递增顺序。

题解中的算法首先将数组排序,确保数字的递增顺序。这样,当数组元素按排序顺序被放置到结果数组中时,可以保证结果数组是递增的。通过使用双端队列来调整每次揭示卡牌后牌的顺序,算法模拟了一个循环过程,其中每次揭示后顶部的卡牌移动到底部。这种循环和排列方法确保了每次从队列中移除的顶部元素正好是下次应当揭示的位置。因此,排序数组的元素可以按照这种方式逐一正确放置,满足题目的输出要求。