【问题标题】:C++ unordered_map operator[ ] vs unordered_map.find() performanceC++ unordered_map operator[ ] vs unordered_map.find() 性能
【发布时间】:2019-12-08 12:59:32
【问题描述】:

我在 interviewbit.com 上解决了一个竞争性编程问题 我基本上使用 unordered_map 来跟踪访问过的数字。当我使用 operator[] 时,我的代码无法及时执行,但是当我使用 find 时它通过了所有测试。两者应该具有相同的时间复杂度。

我尝试使用 clock() 对两个代码进行计时,方法是运行它们 10 次并平均运行时间,它们都给出了或多或少相同的时间。我用的是g++ 7.4.0,而网站提供的环境是g++ 4.8.4。会不会是这个原因。

int Solution::solve(vector<int> &A) {
    unordered_map<long long, int> hashmap;
    for(auto a : A)
        hashmap[a] = 1;
    int res = 0;
    for(int i = 0; i < A.size(); ++i){
        for(int j = i + 1; j < A.size(); ++j){
          // if(hashmap.find((long long)A[i] + A[j]) != hashmap.end())
            if(hashmap[(long long)A[i] + A[j]] == 1)
                ++res;
        }
    }
    return res;
}

问题是在数组中找到其和也存在于数组中的对。当我使用 [] 运算符时,数组大小约为 900 时出现“超出时间限制”。

【问题讨论】:

  • unordered_set 是该问题解决方案的正确数据结构。
  • 输入数组是否保证按任何顺序排列?是否允许负值?
  • @Omnifarious 没有真正的模式,可能存在负值。约束条件不明确,但 O(n^2) 算法应该通过。
  • 出于随机好奇,我想出了一种稍微不同的解决方法,包括对同样具有 n^2 复杂度的值进行排序,但乘数要低得多。大多数情况下,它很难限制它寻找答案的范围。它假定没有重复值。你可以在这里找到它们:godbolt.org/z/JeLsOQ
  • @Omnifarious 对不起,我一开始没看懂,然后就搁置到现在。这种方法似乎类似于 2 指针方法。在实际案例中,这种方法会比我使用的方法更受欢迎吗?

标签: c++ hashmap time-complexity unordered-map


【解决方案1】:

[]-操作符比 find 慢的原因有两个:

  1. [] 运算符在地图上调用非 const 函数,以适当地防止各种优化,例如循环展开。
  2. 更重要的原因:[] 运算符使用其默认值在地图中创建不存在的元素。地图将因之前不在地图中的所有 A[i] + A[j] 对而膨胀,并将其值设置为 0。这将增加地图大小,从而增加时间。

我认为由于以下一个或多个原因,您的性能测量结果显示两种备选方案之间没有差异:

  1. 输入向量太小,无法产生影响
  2. A[i] + A[j] 的大多数组合已经在向量中,因此 unordered_map 没有膨胀到足以产生影响
  3. 您没有优化您的代码(-O3 或 -Os)您的代码

【讨论】:

  • 我使用了在平台上失败的同一个测试用例。我认为我的测量结果没有显示出任何显着差异,因为我没有对其进行优化。由于某种原因,我无法在我的系统上使用 o2 或 o3 进行优化。解决问题后,我将使用结果更新此评论。谢谢
  • 使用 O3 优化,unordered_map.find()unordered_map.at() 快大约 6 倍
猜你喜欢
  • 2011-05-29
  • 1970-01-01
  • 2016-04-09
  • 2014-01-30
  • 1970-01-01
  • 1970-01-01
  • 2018-05-07
  • 1970-01-01
  • 2012-03-17
相关资源
最近更新 更多