题目
思路
- 因为 { 4 , 8 , 15 , 16 , 23 , 42 } \{4,8,15,16,23,42\} {4,8,15,16,23,42}中的数字会在数组a中出现多次,那么尽可能的使用下标靠前的数字进行构造。
- 就可以构造尽可能多的 { 4 , 8 , 15 , 16 , 23 , 42 } \{4,8,15,16,23,42\} {4,8,15,16,23,42}序列,那么删去的最小数目即为 n − c n t n-cnt n−cnt
开始想用窗口,但是窗口只能统计次数,没法区分出这些数字出现的先后顺序。
于是可以维护这6个数字的出现位置:
- 每次遍历这6个数组,如果都非空就可以构成一个题目中的数组。
- 直到某一个q先为空,那么可退出循环。
因为每个下标都只被加入一次且只访问一次,故时间复杂度是 O ( n ) O(n) O(n)的。
代码
#include<bits/stdc++.h>
using namespace std;
unordered_map<int, int> bits_dict = {
{4, 0},
{8, 1},
{15, 2},
{16, 3},
{23, 4},
{42, 5}
};
vector<vector<int>> queues(6);
vector<int> pointers(6);
int main() {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; ++i)
cin >> a[i];
for (int i = 0; i < n; ++i) {
queues[bits_dict[a[i]]].push_back(i);
}
int cnt = 0;
bool a_empty = false;
while (! a_empty) {
int prev = -1, i = 0;
for (auto &q: queues) {
int idx = -1;
while (pointers[i] < q.size()) {
if (q[pointers[i]] > prev) {
idx = q[pointers[i]];
++pointers[i];
break;
} else {
++pointers[i];
}
}
if (idx == -1) {
a_empty = true;
break;
}
prev = idx;
++i;
}
if (!a_empty)
++cnt;
}
printf("%d", n - cnt * 6);
}