24 小R的随机播放顺序 | 豆包MarsCode AI刷题

197 阅读4分钟

问题描述

小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播放歌单的一个特殊规则。以下是规则的详细分析:

1.播放规则:

  • 小R从歌单的第一首歌开始播放,然后将其从歌单中移除。
  • 如果歌单中还有剩余歌曲,小R会将当前歌单中第一首歌移动到歌单的最后一首。
  • 如此反复,直到歌单中没有歌曲为止。

2.模拟过程:

通过一个例子说明操作细节:

  • 给定歌单 [5, 3, 2, 1, 4]:
  1. 播放 5(移除后歌单变为 [3, 2, 1, 4]),将 3 移到末尾,结果是 [2, 1, 4, 3]。
  2. 播放 2(移除后歌单变为 [1, 4, 3]),将 1 移到末尾,结果是 [4, 3, 1]。
  3. 播放 4(移除后歌单变为 [3, 1]),将 3 移到末尾,结果是 [1, 3]。
  4. 播放 1(移除后歌单变为 [3])。
  5. 播放 3(移除后歌单为空)。
  • 最终播放顺序为 [5, 2, 4, 1, 3]。

3.问题要求:

给定歌单的初始顺序,模拟规则,输出真实播放顺序。

解题思路

1.数据结构选择:

  • 歌单的操作需要高效地“取出头部元素”和“将元素插入尾部”。
  • 队列(Queue) 是最佳选择:
  1. 支持从队列头部删除操作(播放)。
  2. 支持在队列尾部插入操作(移动到末尾)。

2.解决步骤:

  • 将所有歌曲顺序存入队列中。
  • 反复模拟播放规则:
  1. 取出队列的头部元素,加入播放顺序结果。
  2. 如果队列非空,将新的队列头部元素移到末尾。
  • 当队列为空时结束。

解题步骤

1.初始化:

  • 创建一个队列 songQueue,用来存储歌单中的歌曲。
  • 创建一个列表 result,存储播放顺序。

2.模拟规则:

  • 取头部歌曲播放: 使用 songQueue.front() 获取队列的头部元素,表示当前播放的歌曲。
  • 移除歌曲: 使用 songQueue.pop() 将头部元素移出队列。
  • 记录结果: 将播放的歌曲加入 result。
  • 移动剩余歌曲:
  1. 如果队列非空,取新的头部元素,用 songQueue.push() 将其插入队列末尾。
  2. 再用 songQueue.pop() 从头部移除。

3.输出结果:

  • 当队列为空时,所有歌曲已播放完毕,结果保存在 result 中。

代码实现

#include <iostream>
#include <vector>
#include <queue> // 引入队列头文件

// 解题函数
std::vector<int> solution(int n, std::vector<int> a) {
    std::vector<int> result;       // 用于存储播放顺序
    std::queue<int> songQueue;     // 队列模拟歌单

    // 1. 将所有歌曲放入队列中
    for (int song : a) {
        songQueue.push(song);
    }

    // 2. 模拟播放过程
    while (!songQueue.empty()) {
        // (1) 取出队列头部的歌曲并移除,将其加入播放结果
        int currentSong = songQueue.front();
        songQueue.pop();
        result.push_back(currentSong);

        // (2) 如果队列中还有歌曲,将新的队列头部移动到末尾
        if (!songQueue.empty()) {
            int nextSong = songQueue.front(); // 获取新的队列头部
            songQueue.pop();                 // 移除头部
            songQueue.push(nextSong);        // 将其移到队列尾部
        }
    }

    return result; // 返回最终播放顺序
}

int main() {
    // 测试用例
    std::vector<int> result1 = {5, 2, 4, 1, 3};
    std::vector<int> result2 = {4, 3, 1, 2};
    std::vector<int> result3 = {1, 3, 5, 2, 6, 4};

    // 输出测试结果
    std::cout << (solution(5, {5, 3, 2, 1, 4}) == result1) << std::endl; // 1表示通过
    std::cout << (solution(4, {4, 1, 3, 2}) == result2) << std::endl;
    std::cout << (solution(6, {1, 2, 3, 4, 5, 6}) == result3) << std::endl;

    return 0;
}

复杂度分析

1.时间复杂度:

  • 每首歌曲从队列移出并最多移到队列尾部一次,队列操作的时间复杂度为O(1)。
  • 总的时间复杂度为 O(n),其中 n 为歌曲数量。

2.空间复杂度:

  • 队列存储 n 首歌曲,空间复杂度为 O(n)。
  • resu1t 也存储 n 首歌曲,因此总空间复杂度为 O(n)。

总结

  • 通过队列高效模拟了小R的播放规则。
  • 本解法结构清晰,时间和空间效率高,适合应对此类序列模拟问题。