青训营X豆包MarsCode 训练营 | 豆包MarsCode AI 刷题

37 阅读4分钟

题目:

问题描述

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

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

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

我的代码:

def solution(n: int, a: list) -> list:
    result = []
    while a:
        result.append(a.pop(0))  # 播放并移除第一首歌
        if a:
            a.append(a.pop(0))  # 将新的第一首歌移到最后
    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])


思路详解:模拟小R的随机播放规则

这道题目要求我们模拟一个随机播放的规则,其中每次播放歌单中的第一首歌,然后将它移除,同时将剩下的歌单中当前的第一首歌移到最后。整个过程一直持续,直到歌单为空。我们的目标是计算并返回歌曲播放的顺序。

1. 问题分析

首先,我们可以把这个问题看成是一个模拟过程的问题。具体来说,每次我们都需要:

  • 播放当前歌单的第一首歌,并将其从歌单中移除。
  • 如果歌单中还有歌曲,移除的歌曲后,当前的第一首歌会被移动到歌单的最后面。

这个过程会一直重复,直到歌单为空。

我们可以利用列表的操作来实现这个过程。每次移除第一首歌可以使用 pop(0),而将当前的第一首歌移到最后可以使用 append()。这两种操作是最直接且符合题目要求的操作。

2. 解题步骤

为了模拟这个过程,我们可以按以下步骤执行:

  • 初始化一个空的 result 列表,用来记录播放的歌曲顺序。

  • 通过 while a: 循环,当歌单 a 非空时,重复以下操作:

    • 使用 pop(0) 从歌单中移除并播放当前第一首歌,然后将其加入 result
    • 如果歌单中仍有歌曲,使用 pop(0) 将当前的第一首歌移到最后,使用 append()
  • 循环结束时,返回 result,即为最终的播放顺序。

3. 代码思路

这道题的代码实现非常直接。我们通过一个 while 循环模拟了整个播放过程。每次播放一首歌并将其移除,之后将当前的第一首歌移到歌单的最后。直到歌单为空,返回播放顺序。

4. 时间复杂度分析

  • 每次操作都涉及对列表的 pop(0)append() 操作。pop(0) 的时间复杂度为 O(n),因为它需要移动列表中的所有元素。而 append() 操作的时间复杂度为 O(1)。
  • 在最坏情况下,我们执行了 npop(0)append() 操作。因此总的时间复杂度是 O(n^2),其中 n 是歌单中的歌曲数。

5. 总结与思考

这个问题考察了我们对基本数据结构(如列表)的操作以及如何模拟问题描述的逻辑。通过 pop(0)append() 来控制歌单的状态是最直接的解法,虽然时间复杂度较高,但对于规模较小的输入是完全可行的。

在实际开发中,可能需要考虑时间复杂度的优化。在这种情况下,如果我们能使用更高效的数据结构(如双端队列 deque),可以在 O(1) 时间内完成两端的操作,从而将总的时间复杂度优化为 O(n)。

6. 高效学习的启示

这道题通过简单的列表操作就能够解决问题,但它也提醒我们在解决实际问题时要考虑数据结构的选择。在处理这种涉及两端操作的问题时,deque 是一个比列表更高效的选择。

此外,模拟类问题的解法通常比较直观,但也需要时刻注意性能优化的问题。通过不断总结和反思,我们可以在类似问题中找到更高效的解法,从而提高解题速度和编程效率。