MEX_Destruction

题目描述

  对于给定的数组(a1,a2,a3...an),选择其中的任意子数组(ai,ai+1...aj),将其用MEX (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的唯一化

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


  1. MEX(The Minist Extensive)指的是一个数组之外的最小的非负的数。因此对于一个含有0或负数的数组,使用MEX失效 ↩︎

  2. 其实就是把边缘出现多个0变成一个0。 ↩︎

posted @   自来人  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示