我正在寻找一种在 C++ 中有效规范化数组的方法,规范化意味着将所有数组值转换为小于或等于 n 的值。所以这:
5235 223 1000 40 40
变成:
4 2 3 1 13 1 2 0 0
这是我的代码

vector<int> normalize_array(vector<int> arr){
    vector<int> tmp(arr), ret(arr.size());

    sort(tmp.begin(), tmp.end());

    for (int i = 0; i < arr.size(); ++i){
        vector<int>::iterator iter = find(tmp.begin(), tmp.end(), arr[i]);
        ret[i] = std::distance(tmp.begin(), iter);
    }

    return ret;
}

输出是 4 2 3 0 0 ,上面的代码不能很好地处理重复元素。
有没有更好的方法来做到这一点?

最佳答案

应用评论中所述的调整,并使用 C++ lambdas:

vector<int> normalize_array(const vector<int> &arr /* O(1) */) {
    vector<int> tmp(arr) /* O(N) */, ret(arr.size()) /* O(1) */;

    sort(tmp.begin(), tmp.end()); // O(N lg N)

    transform(arr.cbegin(), arr.cend(), ret.begin(), [&tmp](int x) {
        return distance(tmp.begin(), lower_bound(tmp.begin(), tmp.end(), x));
    }); // O(N lg N)

    return ret; // O(1) by move semantics
} // O(1) + O(N) + O(1) + O(N lg N) + O(N lg N) == O(N lg N)

Live Example

在以下解决方案中,受到@sachse 的回答的启发,但使用 C++11,通过正确的规范化解决了您的问题,以生成 4 2 3 1 1 ,正如我认为的那样:
vector<int> normalize_array(const vector<int> &arr) {
    if (arr.empty())
        return {};

    vector<int> idx(arr.size()), ret(arr.size());

    iota(idx.begin(), idx.end(), 0);
    sort(idx.begin(), idx.end(),
         [&arr](int i, int j) { return arr[i] < arr[j]; });

    ret[idx[0]] = 1;
    for (size_t i = 1; i < arr.size(); ++i) {
        ret[idx[i]] = ret[idx[i - 1]] + (arr[idx[i]] != arr[idx[i - 1]]);
    }

    return ret;
}

Live Example

关于c++ - 在 C++ 中有效地规范化数组,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26729660/

10-13 06:28