青训营X豆包MarsCode 技术训练营第四课 | 豆包MarsCode AI刷题

50 阅读4分钟

问题描述

小R有一个特殊的歌曲播放规则。给定一个歌单,播放顺序如下:

  1. 首先播放歌单中的第一首歌,并将其从歌单中移除。
  2. 如果歌单中仍然有歌曲,接下来将当前第一首歌移到歌单的最后一首,继续播放。
  3. 这个过程会持续进行,直到歌单中的所有歌曲都播放完毕。

例如,对于歌单 [5, 3, 2, 1, 4],播放顺序应为 [5, 2, 4, 1, 3]。首先播放 5,然后将 3 移动到队列的最后,再播放 2,依此类推。

思路与分析

这个问题实际上是模拟一个特定的队列操作。我们可以将歌单视为一个队列,然后执行如下操作:

  • 从队列中取出第一首歌并播放。
  • 如果队列中还有其他歌曲,则将当前播放的歌曲后面的第一首移到队列的末尾。

由于涉及到队列的先进先出(FIFO)操作,这种情况特别适合使用 队列 数据结构来模拟。

解决方法

我们可以使用 collections.deque,它提供了高效的从队列两端添加和移除元素的操作。具体步骤如下:

  1. 初始化队列:使用 deque(a) 将给定的歌单转化为队列。
  2. 播放过程:循环执行:
    • 从队列的前端移除并播放第一首歌。
    • 如果队列非空,将当前的第一首歌移到队列的末尾。
  3. 终止条件:当队列为空时,表示所有歌曲都已经播放完毕。

代码实现

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

if __name__ == '__main__':
    # 测试案例
    print(solution(n = 5, a = [5, 3, 2, 1, 4]) == [5, 2, 4, 1, 3])
    print(solution(n = 4, a = [4, 1, 3, 2]) == [4, 3, 1, 2])
    print(solution(n = 6, a = [1, 2, 3, 4, 5, 6]) == [1, 3, 5, 2, 6, 4])

代码解释

  1. deque(a):将输入列表 a 转换为双端队列(deque)。队列的特性使得我们能够快速地从队列的两端进行插入和删除操作。

  2. queue.popleft():移除并返回队列的左端元素,也就是当前播放的歌曲。

  3. queue.append(next_song):将从队列中移出的歌曲(即当前队列中的第一首歌)添加到队列的右端。

  4. while queue::循环继续进行,直到队列为空,表示所有歌曲已经播放完。

  5. 返回结果:最终通过 result 列表返回按顺序播放的所有歌曲。

测试案例

  1. 输入 1:

    solution(n = 5, a = [5, 3, 2, 1, 4])
    

    输出

    [5, 2, 4, 1, 3]
    

    过程:

    • 播放 5,队列变为 [3, 2, 1, 4]
    • 播放 2,队列变为 [1, 4, 3]
    • 播放 4,队列变为 [3, 1]
    • 播放 1,队列变为 [3]
    • 播放 3,队列为空,结束。
  2. 输入 2:

    solution(n = 4, a = [4, 1, 3, 2])
    

    输出

    [4, 3, 1, 2]
    

    过程:

    • 播放 4,队列变为 [1, 3, 2]
    • 播放 3,队列变为 [2, 1]
    • 播放 1,队列变为 [2]
    • 播放 2,队列为空,结束。
  3. 输入 3:

    solution(n = 6, a = [1, 2, 3, 4, 5, 6])
    

    输出

    [1, 3, 5, 2, 6, 4]
    

    过程:

    • 播放 1,队列变为 [2, 3, 4, 5, 6]
    • 播放 3,队列变为 [4, 5, 6, 2]
    • 播放 5,队列变为 [6, 2, 4]
    • 播放 2,队列变为 [4, 6]
    • 播放 6,队列变为 [4]
    • 播放 4,队列为空,结束。

时间复杂度分析

  • 队列操作popleft()append())的时间复杂度是 O(1),因为 deque 提供了高效的双端操作。
  • 循环次数n(歌单的长度)。每次操作都涉及对队列的访问和修改,因此总的时间复杂度为 O(n)

结论

该算法通过使用队列来模拟小R的播放规则,具有简单的逻辑结构和高效的时间复杂度。使用 deque 数据结构能确保每次从队列两端的操作都是常数时间,这使得算法在处理较大输入时也能保持高效。