蓝桥杯 2019-A-修改数组(C++ 并查集解法)

题目

蓝桥杯 2019-A-修改数组(C++ 并查集解法)_第1张图片

第一版 哈希表暴力模拟(超时)

#include 

#include 

using namespace std;

int main() {
    // map index;
    bool index[1000002] = {0}; 
    int n;
    cin >> n;
    vector num(n, 0);
    for (int i = 0; i < n; i++) {
        int x = 0;
        cin >> x;
        while (index[x]) { // 若原数组 x 已经出现过
            x++;
        }
        index[x] = true;
        // num.emplace_back(x);
        num[i] = x;
    }
    for(auto x : num){
        cout << x<<' ';
    }

    return 0;
}

超时。 果然偷懒不可取

超时原因

归根结底,超时在寻找替代的数字这个过程上,暴力模拟是一次次的加上去,然后再判断哈希表中是否有重复,若有重复则再加一,一直加到没有重复为止。

思考其时间复杂度,假设在最坏的情况下,输入的数组全部为相同的数,比如全是 n 个 1,则其循环过程在每次分别为: 1次 、2次 、3次 … n 次。 时间复杂度应该在 O ( n 2 ) O(n^2) O(n2)。 而 n 最高能取到 1 0 6 10^6 106。所以超时是在所难免的。

那么我们的目标转化为快速的获取替换数。即我们希望有一个方法或者说数据结构,可以使得我们输入初始数 x ,直接得到合法的替换数 y,而不用从 x 一次次的加1加到 y 为止。

思考其特征,一对连续的数,其输出的 y (这里的y 即合法的替换数)应该是相同的,那么可以把这些连续的数看做一个集合,于是乎,并查集的思路出现了。

第二版 并查集(通过)

既然知道采用并查集了,我们需要捋清楚将两个数合并的条件,即两个数是连续的,若两个数连续,则他们属于一个集合。

其次我们需要定义一下根节点,因为我们需要这些连续的数都指向一个合法的替换数,所以将其定义为父节点。

需要注意的是,不同于一般并查集,根节点我们这里有特殊定义,所以在集合之间的合并,不能采取一般的按秩合并来做,而是直接指向较大数的父节点。即

// fa 为存储的并查集, find 得到其根节点
fa[x] = find(x + 1);
#include 

#include 

using namespace std;
#define MAX 1000002

// 并查集定义
int fa[MAX] = {0};     // 并查集
// int order[MAX] = {0};  // 并查集秩 rank 是 C++ 关键词,所以换用 order

inline void init(void) {
    for (int i = 0; i < MAX; i++) {
        fa[i] = i;
        // order[i] = 1;
    }
}

inline int find(int x) {
    if (fa[x] == x) {
        return x;
    } else {
        fa[x] = find(fa[x]);
        return fa[x];
    }
}

// inline void merge(int a, int b) {
//     int x = find(a), y = find(b);
//     // fa[x] = y;
//     if (order[x] <= order[y]) {
//         fa[x] = y;
//     } else
//         fa[y] = x;
//     if (order[x] == order[y] && x != y) {
//         order[y]++;
//     }
// }

int main() {
    // map fa;
    int n;
    cin >> n;
    vector num(n, 0);
    init();
    for (int i = 0; i < n; i++) {  // 接受输入
        int x = 0;
        cin >> x;
        int temp = find(x);
        num[i] = temp;
        fa[temp] = find(temp + 1);
    }
    for (auto x : num) {
        cout << x << ' ';
    }

    return 0;
}

你可能感兴趣的:(蓝桥杯,c++,蓝桥杯,数据结构)