【问题标题】:Most efficient way to delete unique elements from array从数组中删除唯一元素的最有效方法
【发布时间】:2018-03-31 08:52:36
【问题描述】:

在 C++ 中消除数组中唯一元素的有效方法是什么?

给定数组:

9, 8, 4, 9, 21, 3, 1, 4, 6, 2, 5, 6, 7, 12, 3, 6, 9, 1, 3    // keep duplicates, delete uniques

输出:

9, 4, 9, 3, 1, 4, 6, 6, 3, 6, 9, 1, 3    // all duplicates

【问题讨论】:

  • std::setstd::unordered_set 中进行簿记的循环
  • @Jenin 你可以对原始数组进行排序吗?
  • 循环,将元素添加到std::set,如果尝试时该元素已经在集合中,请将其添加到重复项列表中。
  • 这是昨天才被问到的……您至少应该尝试自己解决问题
  • @VladfromMoscow,不,原件不允许排序

标签: c++ arrays algorithm c++11 duplicates


【解决方案1】:

我可能会这样做:

#include <algorithm>
#include <iostream>
#include <vector>
#include <map>

int main(int argc, char* argv[]) {
    std::vector<int> nums = {9, 8, 4, 9, 21, 3, 1, 4, 6, 2, 
                             5, 6, 7, 12, 3, 6, 9, 1, 3};
    // build histogram
    std::map<int, int> counts;
    for (int i : nums) ++counts[i];
    // copy elements that appear more than once
    std::vector<int> result;
    std::copy_if(nums.begin(), nums.end(),
                 std::back_inserter(result), 
                 [&](int x){ return counts[x] > 1; });
    // print result
    for (int i : result) {
        std::cout << i << " ";
    }
    std::cout << "\n";
}

输出是:

$ g++ test.cc -std=c++11 && ./a.out
9 4 9 3 1 4 6 6 3 6 9 1 3

这是两遍,你构建了一个 BST。如果您觉得这太慢了,您可以尝试使用std::unordered_map 构建直方图,它在插入和查找方面具有更好的复杂性特征。

如果您希望从原始向量中删除重复项而不是构建另一个向量,则可以使用erase-remove idiom。 (这留给读者作为练习。)

【讨论】:

  • 使用unordered_map 代替map 可以加快速度
  • “我不认为你会更快地得到这个。”实际上,可以使用 unorderd_map 来完成。不是 O(n log n),而是 O(n)。我认为这算是“明显更快”。
  • @JimMischel 虽然理论上 O(n) 比 O(n log n) 快,但在实践中不一定明显快。 (FWIW 我删除了该部分,赞成在std::unordered_map 上添加注释。)
  • unordered_map 的平均操作复杂度为O(n),而不是在最坏的情况下。
  • @DAle:是的,unordered_map 的平均情况复杂度为 O(n),最坏情况复杂度为 O(n log n)。如果插入的项目全部落入极少数的桶中,就会出现最坏的情况。也就是说,大量的哈希冲突。没有故意生成的病理数据,我在实践中从未见过这样的事情发生。
【解决方案2】:

我会使用 C++ 集合,因为它们具有对数复杂性(编辑:正如 Scheff 所说)。

此解决方案的算法复杂度为 O(n log n):

#include <set>
#include <iostream>

int main(int argc, char** argv) {
    int nums[] = {9, 8, 4, 9, 21, 3, 1, 4, 6, 2, 5, 6, 7, 12, 3, 6, 9, 1, 3};
    std::set<int> s;
    std::set<int> dups;

    for (int i = 0; i < 19; ++i)
        if (!s.insert(nums[i]).second)
            dups.insert(nums[i]);

    for (int i = 0; i < 19; ++i)
        if (dups.find(nums[i]) != dups.end())
            std::cout << " " << nums[i];
    std::cout << std::endl;

    return 0;
}

【讨论】:

    【解决方案3】:
    void rmdup(int *array, int length)
    {
        int *current , *end = array + length - 1;
    
        for ( current = array + 1; array < end; array++, current = array + 1 )
        {
            while ( current <= end )
            {
                if ( *current == *array )
                {
                    *current = *end--;
                }
                else
                {
                    current++;
                }
            }
        }
    }
    

    //希望对你有帮助

    【讨论】:

    • 相对于赋值函数没有意义。
    【解决方案4】:

    这个怎么样?

    #include <set>
    #include <vector>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    int main(int argc, char** argv) {
        vector<int> nums = {9, 8, 4, 9, 21, 3, 1, 4, 6, 2, 5, 6, 7, 12, 3, 6, 9, 1, 3};
        std::set<int> s;
        vector<int> dups;
    
        for(auto i:nums)
            if (!s.insert(i).second)
                dups.push_back(i);
    
        for_each(dups.begin(),dups.end(),[](int a){cout<<a<<" ";});
        cout << endl;
    
        return 0;
    }
    

    只有一次通行证。

    【讨论】:

    • 一次通过,但输出与所需不同
    猜你喜欢
    • 2012-10-22
    • 2020-06-05
    • 2019-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-01
    • 1970-01-01
    相关资源
    最近更新 更多