问题描述
小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]
问题分析
小R的音乐播放规则如下:
- 从歌单中播放第一首歌,并将其从歌单中移除。
- 如果歌单中还有歌曲,将当前的第一首歌移到最后一首。
- 重复上述过程,直到歌单中没有任何歌曲。
通过样例可以观察到,播放顺序呈现出一种特定的模式,需要通过模拟这个过程来确定最终的播放顺序。
解决方案
我们可以利用 collections.deque(双端队列)来高效地实现这一过程。双端队列支持高效的从队列两端进行元素的添加和移除操作。
具体步骤如下:
-
初始化一个双端队列
queue,并将输入的歌单a转换为双端队列。 -
使用一个循环,直到队列为空:
- 从队列头部弹出第一首歌,并将其添加到结果列表中。
- 如果队列中还有歌曲,继续弹出当前的第一首歌,并将其追加到队列的尾部。
-
最终,结果列表
result中存储的就是真实的播放顺序。
代码实现
from collections import deque
def solution(n, a):
result = []
queue = deque(a)
while queue:
first = queue.popleft()
result.append(first)
if queue:
# 将下一个元素移动到队列的尾部,模拟下一次的“接下来”操作
next_song = queue.popleft()
queue.append(next_song)
return result
**
代码解释
-
导入
deque:from collections import deque**
deque是 Python 标准库中collections模块提供的一个双端队列实现,支持高效的头部和尾部操作。 -
初始化结果列表和队列:
result = [] queue = deque(a)**
将输入的歌单
a转换为双端队列queue,并初始化结果列表result。 -
循环处理队列:
while queue: first = queue.popleft() result.append(first) if queue: next_song = queue.popleft() queue.append(next_song)**
queue.popleft():从队列头部移除并返回一个元素。result.append(first):将移除的元素添加到结果列表中。- 如果队列不为空,继续移除下一个元素,并将其追加到队列尾部。
-
返回结果:
return result**
最终返回结果列表
result,其中存储了真实的播放顺序。
复杂度分析
- 时间复杂度:O(n),其中 n 是歌曲的数量。每个歌曲最多被移除和添加到队列尾部一次。
- 空间复杂度:O(n),需要额外的空间存储队列和结果列表。
双端队列
C++中的STL库提供了deque用于实现双端队列,Python的collections也提供了双端队列的库。
1. 定义
双端队列(Deque,全称 Double-Ended Queue)是一种特殊的队列,允许在队列的两端(前端和后端)进行插入和删除操作。双端队列结合了队列(Queue)和栈(Stack)的特性,支持从队列的前端和后端添加或删除元素。
2. 特点
- 两端操作:可以在队列的前端(左端)和后端(右端)进行插入和删除操作。
- 高效性:通常支持高效的插入和删除操作(O(1) 时间复杂度)。
- 灵活性:既可以作为队列使用(FIFO,先进先出),也可以作为栈使用(LIFO,后进先出)。