题目描述
对于给定的数组(a1,a2,a3...an),选择其中的任意子数组(ai,ai+1...aj),将其用MEX[1] (ai,ai+1...aj)代替。那么最少需要几次操作才可以将数组全部变成0。
题目链接:https://codeforces.com/problemset/problem/2049/A
题目解析
可以看出解题目的重点是数组中0的位置,针对0的位置分为四种情况:
- 数组全是0,返回0。
- 数组没有0,返回1
- 数组中0只在边缘,返回1。
- 数组中0出现在中间,返回2。
得出以下代码:
void mex_destruction() {
vector<int>array;
get_array(array);
int number_array = array.size();
vector<int> loc_0 = get_location(array);
// 全是0的情况
if(loc_0.size() == number_array){
cout<<0<<'\n';
return;
}
for(int & it : loc_0){
// 如果中间出现0,那么就返回2(表示一定会出现2个以上的字串)
if(it!=0 && it!=number_array-1){
cout<<2<<"\n";
return;
}
}
cout<<"1"<<'\n';
}
vector<int> get_location(vector<int> array) {
vector<int>location;
for(int i=0 ;i<array.size();i++){
if(array[i] == 0){
location.push_back(i);
}
}
return location;
}
不过居然出错了,经过分析,发现有一种恶心的情况:
1
4
0 0 1 2
在该种情况下,程序判定第二个0在中间,但是本质上还是在边缘,为了处理这种情况,需要添加边缘0的唯一化[2]
std::vector<int> removeEdgeZeros(const std::vector<int> arr) {
int n = arr.size();
int start = 0;
int end = n - 1;
while (start < n && arr[start] == 0) {
start++;
}
while (end >= 0 && arr[end] == 0) {
end--;
}
if (start > end) {
return {};
}
return vector<int>(arr.begin() + start, arr.begin() + end + 1);
}
完美收官。可以看到性能还是不错的。算法的时间复杂度也控制在O(n),主要的时间消耗是在边缘0的唯一化和找出全部0的位置。
完整代码
//
// Created by FreeMan on 25-1-7.
//
#include<bits/stdc++.h>
void mex_destruction();
void get_array(std::vector<int>& array);
std::vector<int> removeEdgeZeros(const std::vector<int> arr);
std::vector<int> get_location(std::vector<int> array);
using namespace std;
int main(){
int number;
cin>>number;
while (number>0){
mex_destruction();
number--;
}
}
void mex_destruction() {
vector<int>array;
get_array(array);
int number_array = array.size();
vector<int> loc_0 = get_location(array);
// 全是0的情况
if(loc_0.size() == number_array){
cout<<0<<'\n';
return;
}
for(int & it : loc_0){
// 如果中间出现0,那么就返回2(表示一定会出现2个以上的字串)
if(it!=0 && it!=number_array-1){
cout<<2<<"\n";
return;
}
}
cout<<"1"<<'\n';
}
vector<int> get_location(vector<int> array) {
vector<int>location;
for(int i=0 ;i<array.size();i++){
if(array[i] == 0){
location.push_back(i);
}
}
return location;
}
void get_array(vector<int> & array) {
int number_array;
cin>>number_array;
while(number_array>0){
int temp_number;
cin>>temp_number;
array.push_back(temp_number);
number_array--;
}
array = removeEdgeZeros(array);
}
std::vector<int> removeEdgeZeros(const std::vector<int> arr) {
int n = arr.size();
int start = 0;
int end = n - 1;
while (start < n && arr[start] == 0) {
start++;
}
while (end >= 0 && arr[end] == 0) {
end--;
}
if (start > end) {
return {};
}
return vector<int>(arr.begin() + start, arr.begin() + end + 1);
}
反思
其实有一种新的思考方式:找被0包裹的字串数。可以参考篇文章: https://blog.csdn.net/qq_68286180/article/details/144634211