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

40 阅读3分钟

学习笔记:特殊的随机播放规则


题目描述

小R使用一种特殊的随机播放规则:

  1. 播放歌单中第一首歌,并将其移除。
  2. 如果歌单中还有歌,则将新的第一首歌移到歌单末尾。
  3. 重复上述过程,直到歌单为空。
输入
  • 一个整数 n,表示歌曲数量。
  • 一个长度为 n 的数组 a,表示歌单中歌曲的 ID。
输出
  • 一个数组,表示小R的真实播放顺序。

题目解析

1. 思路分析
  1. 模拟规则:题目本质是模拟歌单的播放顺序和移动过程。每次都从歌单头部弹出一首歌(模拟播放),然后检查剩余的歌曲是否需要移动。

  2. 数据结构选择

    • 数组模拟:需要频繁对数组首尾操作,效率较低。
    • 双端队列(deque) :支持 O(1) 的头部弹出和尾部添加,非常适合这种规则的模拟。
  3. 算法步骤

    • 初始化一个双端队列存储歌单。
    • 每次从队列头部弹出一首歌,加入结果。
    • 如果队列非空,则将新的第一首歌移动到队列尾部。
    • 重复上述操作直到队列为空。
2. 示例分析

示例1:n=5, a=[5, 3, 2, 1, 4]

  • 初始化:playlist = deque([5, 3, 2, 1, 4])result = []
  • 第1步:播放并移除5,结果[5],剩余[3, 2, 1, 4] -> 将3移到末尾 -> [2, 1, 4, 3]
  • 第2步:播放并移除2,结果[5, 2],剩余[1, 4, 3] -> 将1移到末尾 -> [4, 3, 1]
  • 第3步:播放并移除4,结果[5, 2, 4],剩余[3, 1] -> 将3移到末尾 -> [1, 3]
  • 第4步:播放并移除1,结果[5, 2, 4, 1],剩余[3] -> 将3移到末尾 -> [3]
  • 第5步:播放并移除3,结果[5, 2, 4, 1, 3],队列为空。

输出:[5, 2, 4, 1, 3]


代码实现

from collections import deque

def solution(n: int, a: list) -> list:
    # 初始化一个双端队列
    playlist = deque(a)
    result = []

    # 模拟随机播放规则
    while playlist:
        # 播放并移除第一首歌
        result.append(playlist.popleft())
        # 如果队列非空,将新的第一首歌移到末尾
        if playlist:
            playlist.append(playlist.popleft())

    return result

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

知识总结

1. 数据结构:双端队列(deque)

双端队列是解决队列头部和尾部操作的高效工具,支持以下操作:

  • popleft():从队列头部弹出元素,时间复杂度 O(1)。
  • append(x):将元素添加到队列尾部,时间复杂度 O(1)。
2. 模拟问题
  • 模拟类问题通常需要选择合适的数据结构(如队列、栈)简化操作。
  • 通过模拟过程理解规则,再设计高效的实现。
3. 算法复杂度
  • 时间复杂度:每首歌最多操作两次(移出队列 + 移到尾部),总复杂度 O(n)。
  • 空间复杂度:使用双端队列存储 n 首歌,复杂度为 O(n)。

学习建议

  1. 灵活选择数据结构:根据题目要求,选用合适的数据结构可以显著提升性能。多练习队列、栈相关题目,培养对数据结构的直觉。
  2. 手动模拟过程:在思考复杂规则时,先手动模拟小样例,理清思路后再编写代码。
  3. 实践优化:初始解法可用列表模拟,但性能较差;在理解性能瓶颈后尝试使用更高效的工具(如 deque)。

图解

步骤队列内容播放结果
初始化[5, 3, 2, 1, 4][]
第1步[3, 2, 1, 4][5]
第2步[2, 1, 4, 3][5, 2]
第3步[1, 4, 3][5, 2, 4]
第4步[4, 3, 1][5, 2, 4, 1]
第5步[3][5, 2, 4, 1, 3]