小R的随机播放顺序 | 豆包MarsCode AI刷题

85 阅读3分钟

问题描述

小R有一个特殊的随机播放规则。他首先播放歌单中的第一首歌,播放后将其从歌单中移除。如果歌单中还有歌曲,则会将当前第一首歌移到最后一首。这个过程会一直重复,直到歌单中没有任何歌曲。

例如,给定歌单 [5, 3, 2, 1, 4],真实的播放顺序是 [5, 2, 4, 1, 3]

保证歌曲中的id两两不同。

问题分析

题目描述了一种特殊的随机播放规则,具体过程如下:

  1. 播放并移除第一首歌:将歌单的第一首歌播放,并将其从歌单中移除。
  2. 移动新第一首歌到末尾:如果歌单中还有歌曲,则将新的第一首歌移到最后一首。
  3. 重复上述步骤,直到歌单为空。

给定一个初始歌单,要求输出按照上述规则播放的实际顺序。


示例分析

假设初始歌单为 [5, 3, 2, 1, 4]

  1. 歌单初始状态为 [5, 3, 2, 1, 4]

    • 播放 5,移除后歌单变为 [3, 2, 1, 4]
    • 3 移到末尾,歌单变为 [2, 1, 4, 3]
  2. 歌单状态为 [2, 1, 4, 3]

    • 播放 2,移除后歌单变为 [1, 4, 3]
    • 1 移到末尾,歌单变为 [4, 3, 1]
  3. 歌单状态为 [4, 3, 1]

    • 播放 4,移除后歌单变为 [3, 1]
    • 3 移到末尾,歌单变为 [1, 3]
  4. 歌单状态为 [1, 3]

    • 播放 1,移除后歌单变为 [3]
    • 3 移到末尾,歌单保持不变。
  5. 歌单状态为 [3]

    • 播放 3,移除后歌单为空。

最终播放顺序为 [5, 2, 4, 1, 3]


解题思路

可以模拟这一过程来实现,具体步骤如下:

  1. 使用一个队列来模拟歌单的操作。

  2. 按照规则进行循环:

    • 移除队列的第一个元素并记录为播放的歌曲;
    • 如果队列不为空,将新的第一首歌移到队列末尾。
  3. 当队列为空时,结束操作,返回记录的播放顺序。

算法实现

使用 Python 实现该算法,代码如下:

def solution(n: int, a: list) -> list:
    result = []  # 用于记录实际播放顺序

    while a:
        # 播放并移除第一首歌
        result.append(a.pop(0))  # 删除并记录第一个元素
        if a:
            # 将新的第一首歌移到末尾
            a.append(a.pop(0))

    return result

代码逻辑

  1. pop(0)

    • 用于从列表的开头删除元素,同时返回该元素。
    • 模拟“移除第一首歌”的操作。
  2. append(pop(0))

    • 从列表开头删除一个元素,并将其添加到列表末尾。
    • 模拟“将第一首歌移动到末尾”的操作。
  3. 循环条件

    • 每次循环播放一首歌并执行操作,直到列表为空。

时间复杂度分析

  • pop 的开销pop 的复杂度为 O(n),因为需要将剩余元素前移。
  • 每次操作都要处理 n,n−1,…,1 个元素,因此总复杂度为 O(n2^2)。

优化建议

如果歌单较大(如上万首歌),建议使用队列结构(如 collections.deque),避免 pop(0) 的高开销,从而将时间复杂度优化为 O(n)。

from collections import deque

def solution(n: int, a: list) -> list:
    # 使用队列来模拟歌单
    queue = deque(a)
    result = []

    while queue:
        # 播放并移除第一首歌
        result.append(queue.popleft())
        if queue:
            # 将新的第一首歌移到末尾
            queue.append(queue.popleft())

    return result