497队列+24小R的随机播放顺序解答C++|豆包MarsCode AI刷题

57 阅读5分钟

497队列+24小R的随机播放顺序解答C++|豆包MarsCode AI刷题

497问题描述

给定一个长度为 n 的序列 𝑎1,𝑎2,…,an,你可以选择删去其中最多 n−1 个数,得到一个新序列 𝑏1,𝑏2,…,bm (1≤m≤n),新序列保留原来的相对顺序。你的目标是删除某些数,使得新序列的第 i 个数 bi=i。现在需要求出最少删除多少个数才能得到这样的序列,如果无法得到,输出−1。

例如,对于序列 [1, 4, 2, 3, 5],删除第 2 个和第 5 个元素后,可以得到序列 [1, 2, 3]

测试样例

样例1:

输入:n = 5 ,a = [1, 4, 2, 3, 5]
输出:2

样例2:

输入:n = 3 ,a = [3, 3, 2]
输出:-1

样例3:

输入:n = 5 ,a = [1, 2, 3, 4, 5]
输出:0

详细解答

注意事项:

1.代码的时间复杂度不要过高

2.找到i=bi的突破技巧

3.题目的具体要求(题目没有要求保存输出)

思路

1.对于题目中i=bi,思路往往是使用for循环直接判断是否相等,但是如果不相等需要删除对应的结点,删除过后其他元素值如果前移,会造成时间复杂度过高(需要嵌套for循环),而题目中并没有要求求出删除过后的结点及值,所以我们并不需要做删除处理

2.对于如何使用循环来判断i是否等于bi,我们定义一个初始值value=1,为什么是1呢,由实例可得,该数组的计数从1开始,所以第一个数的i=1,第二个符合要求的值应该为i++,如果不符合,我们不予i++,对于所应删除的结点,我们使用delete_count计数。

代码

#include <iostream>
#include <vector>

using namespace std;

int solution(int n, vector<int>& a) {
    int expected_value = 1; // 新序列b的当前符合要求的值
    int delete_count = 0; // 删除的元素数量

    for (int num : a) {
        if (num == value) {
            // 如果当前数等于对应的值,则更新判断值
            value++;
        } else {
            // 如果当前数不等于,则增加删除计数
            delete_count++;
        }
    }

    // 检查是否构建了一个完整的序列
    if (delete_count == n) {
        return -1; // 没有找到任何有效的序列
    } else {
        return delete_count; // 返回需要删除的元素数量
    }
}

int main() {
    vector<int> v1 = {1, 4, 2, 3, 5};
    vector<int> v2 = {3, 3, 2};
    vector<int> v3 = {1, 2, 3, 4, 5};

    cout << (solution(5, v1) == 2) << endl;
    cout << (solution(3, v2) == -1) << endl;
    cout << (solution(5, v3) == 0) << endl;
    return 0;
}

24问题描述

小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]

解析

为了解决这个问题,我们需要模拟小R的播放规则。规则很简单:首先播放歌单的第一首歌,并将其从歌单中移除,然后将当前的第一首歌(也就是原来第二首歌,现在因为第一首歌被移除了而成为了第一首)移动到歌单的末尾。这个过程一直重复,直到歌单为空。

流程

流程分析
  1. 初始化

    • 使用输入的歌单a初始化一个std::deque<int>,名为playlistdeque(双端队列)被选择是因为它支持在头部和尾部进行高效的插入和删除操作。
    • 初始化一个空的std::vector<int>,名为playOrder,用于存储播放顺序。
  2. 播放循环

    • 使用一个while循环来遍历playlist,直到playlist为空。
  3. 播放当前歌曲

    • 在每次循环的开始,从playlist的头部取出当前第一首歌(currentSong = playlist.front())。
    • 将这首歌添加到playOrder的末尾(playOrder.push_back(currentSong))。
    • playlist中移除这首歌(playlist.pop_front())。
  4. 移动下一首歌到末尾(如果歌单不为空)

    • 检查playlist是否为空。如果不为空,则执行以下操作:

      • playlist的头部取出新的第一首歌(实际上是原来的第二首歌,因为第一首歌已经被移除了)(nextFirstSong = playlist.front())。
      • playlist中移除这首歌(playlist.pop_front())。这一步是模拟将这首歌移动到末尾之前的准备步骤,因为在deque中直接移动到末尾是不必要的(因为我们已经移除了它,并且稍后会添加到末尾)。
      • 将这首歌添加到playlist的末尾(playlist.push_back(nextFirstSong)),模拟了规则中的“将当前第一首歌移到最后一首”的操作。
  5. 结束循环

    • playlist为空时,循环结束。
#include <iostream>
#include <vector>
#include <deque> // 使用deque是因为它支持高效的头部和尾部操作

std::vector<int> solution(int n, std::vector<int> a) {
    std::deque<int> playlist(a.begin(), a.end()); // 使用deque来存储歌单,以便高效地进行头部和尾部的插入和删除操作
    std::vector<int> playOrder; // 存储播放顺序

    while (!playlist.empty()) {
        int currentSong = playlist.front(); // 获取当前第一首歌
        playOrder.push_back(currentSong); // 添加到播放顺序中
        playlist.pop_front(); // 从歌单中移除这首歌
        
        if (!playlist.empty()) {
            int nextFirstSong = playlist.front(); // 获取新的第一首歌(原第二首歌)
            playlist.pop_front(); // 从歌单中移除这首歌(模拟移动到末尾之前的操作)
            playlist.push_back(nextFirstSong); // 将这首歌移动到歌单末尾
        }
    }

    return playOrder;
}


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;
    std::cout << (solution(4, {4, 1, 3, 2}) == result2) << std::endl;
    std::cout << (solution(6, {1, 2, 3, 4, 5, 6}) == result3) << std::endl;
}