问题描述
小R有一个特殊的随机播放规则。他首先播放歌单中的第一首歌,播放后将其从歌单中移除。如果歌单中还有歌曲,则会将当前第一首歌移到最后一首。这个过程会一直重复,直到歌单中没有任何歌曲。
例如,给定歌单 [5, 3, 2, 1, 4],真实的播放顺序是 [5, 2, 4, 1, 3]。
保证歌曲中的id两两不同。
问题分析
题目描述了一种特殊的随机播放规则,具体过程如下:
- 播放并移除第一首歌:将歌单的第一首歌播放,并将其从歌单中移除。
- 移动新第一首歌到末尾:如果歌单中还有歌曲,则将新的第一首歌移到最后一首。
- 重复上述步骤,直到歌单为空。
给定一个初始歌单,要求输出按照上述规则播放的实际顺序。
示例分析
假设初始歌单为 [5, 3, 2, 1, 4]:
-
歌单初始状态为
[5, 3, 2, 1, 4]:- 播放
5,移除后歌单变为[3, 2, 1, 4]。 - 将
3移到末尾,歌单变为[2, 1, 4, 3]。
- 播放
-
歌单状态为
[2, 1, 4, 3]:- 播放
2,移除后歌单变为[1, 4, 3]。 - 将
1移到末尾,歌单变为[4, 3, 1]。
- 播放
-
歌单状态为
[4, 3, 1]:- 播放
4,移除后歌单变为[3, 1]。 - 将
3移到末尾,歌单变为[1, 3]。
- 播放
-
歌单状态为
[1, 3]:- 播放
1,移除后歌单变为[3]。 - 将
3移到末尾,歌单保持不变。
- 播放
-
歌单状态为
[3]:- 播放
3,移除后歌单为空。
- 播放
最终播放顺序为 [5, 2, 4, 1, 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)):- 从列表开头删除一个元素,并将其添加到列表末尾。
- 模拟“将第一首歌移动到末尾”的操作。
-
循环条件:
- 每次循环播放一首歌并执行操作,直到列表为空。
时间复杂度分析
pop的开销:pop的复杂度为 O(n),因为需要将剩余元素前移。- 每次操作都要处理 n,n−1,…,1 个元素,因此总复杂度为 O(n)。
优化建议
如果歌单较大(如上万首歌),建议使用队列结构(如 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