问题描述
小R有一个特殊的随机播放规则。他首先播放歌单中的第一首歌,播放后将其从歌单中移除。如果歌单中还有歌曲,则会将当前第一首歌移到最后一首。这个过程会一直重复,直到歌单中没有任何歌曲。
例如,给定歌单 [5, 3, 2, 1, 4],真实的播放顺序是 [5, 2, 4, 1, 3]。
保证歌曲中的id两两不同。
测试样例
样例1:
输入:
n = 5 ,a = [5, 3, 2, 1, 4]
输出:[5, 2, 4, 1, 3]
样例2:
输入:
n = 4 ,a = [4, 1, 3, 2]
输出:[4, 3, 1, 2]
样例3:
输入:
n = 6 ,a = [1, 2, 3, 4, 5, 6]
输出:[1, 3, 5, 2, 6, 4]
解题思路
这个问题可以通过模拟整个播放和移动的过程来解决。根据题目描述,每次我们取出当前列表的第一个元素作为播放的歌曲,然后将这首歌曲从列表中移除。如果列表中还有歌曲,则将当前的第一首歌移到最后一首。这个过程一直重复,直到列表为空。
图解步骤
以样例 [5, 3, 2, 1, 4] 为例,操作步骤如下:
- 播放 5,列表变为
[3, 2, 1, 4]。 - 将 3 移到末尾,列表变为
[2, 1, 4, 3]。 - 播放 2,列表变为
[1, 4, 3]。 - 将 1 移到末尾,列表变为
[4, 3, 1]。 - 播放 4,列表变为
[3, 1]。 - 将 3 移到末尾,列表变为
[1, 3]。 - 播放 1,列表变为
[3]。 - 播放 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
时间和空间复杂度分析
时间复杂度: 每次处理一个元素需要进行两次列表操作(pop(0) 和 append),每个 pop(0) 操作的时间复杂度为 O(n),因为它需要移动列表中的所有其他元素。因此,总的时间复杂度为 O(n^2),其中 n 是列表的长度。
空间复杂度: 这个算法使用了额外的列表 result 来存储播放顺序,因此空间复杂度为 O(n),其中 n 是输入列表的长度。
优化思考
这个解法中,pop(0) 是一个较为耗时的操作,因为每次调用都会导致数组中剩余元素的移动。如果能使用一个更高效的数据结构来避免这种开销,比如双端队列(collections.deque),那么性能会有所提升。使用 deque 可以将 pop(0) 和 append 操作的复杂度降至 O(1),从而使得总体时间复杂度降为 O(n)。