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的播放规则。规则很简单:首先播放歌单的第一首歌,并将其从歌单中移除,然后将当前的第一首歌(也就是原来第二首歌,现在因为第一首歌被移除了而成为了第一首)移动到歌单的末尾。这个过程一直重复,直到歌单为空。
流程
流程分析
-
初始化
- 使用输入的歌单
a初始化一个std::deque<int>,名为playlist。deque(双端队列)被选择是因为它支持在头部和尾部进行高效的插入和删除操作。 - 初始化一个空的
std::vector<int>,名为playOrder,用于存储播放顺序。
- 使用输入的歌单
-
播放循环
- 使用一个
while循环来遍历playlist,直到playlist为空。
- 使用一个
-
播放当前歌曲
- 在每次循环的开始,从
playlist的头部取出当前第一首歌(currentSong = playlist.front())。 - 将这首歌添加到
playOrder的末尾(playOrder.push_back(currentSong))。 - 从
playlist中移除这首歌(playlist.pop_front())。
- 在每次循环的开始,从
-
移动下一首歌到末尾(如果歌单不为空)
-
检查
playlist是否为空。如果不为空,则执行以下操作:- 从
playlist的头部取出新的第一首歌(实际上是原来的第二首歌,因为第一首歌已经被移除了)(nextFirstSong = playlist.front())。 - 从
playlist中移除这首歌(playlist.pop_front())。这一步是模拟将这首歌移动到末尾之前的准备步骤,因为在deque中直接移动到末尾是不必要的(因为我们已经移除了它,并且稍后会添加到末尾)。 - 将这首歌添加到
playlist的末尾(playlist.push_back(nextFirstSong)),模拟了规则中的“将当前第一首歌移到最后一首”的操作。
- 从
-
-
结束循环
- 当
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;
}