向量中的第一个副本
我有以下代码在整数向量中找到第一个重复项:
#include <iostream>
#include <vector>
#include <unordered_set>
using namespace std;
int find_duplicate(const vector<int> &v)
{
unordered_set<int> numbers;
for(const auto num : v)
{
if (numbers.count(num) > 0)
{
return num;
}
else
{
numbers.insert(num);
}
}
return -1;
}
int main()
{
std::vector<int> v = {1, 3, 4, 5, 3, 2, 3, 6, 2};
cout << find_duplicate(v);
return 0;
}
我想知道是否有更简洁的方式使用 C++ std 库算法来编写它?
find_duplicate 不应修改输入向量,也不应复制它。
回答
C++ 标准库是围绕迭代器而不是索引构建的。如果您更改find_duplicate函数以返回迭代器,则可以简明地写为:
auto find_duplicate(const vector<int> &v)
{
unordered_set<int> numbers;
return std::find_if(v.begin(), v.end(),
[&](int num) { return !numbers.insert(num).second; });
}
请注意,unordered_set<T>::insert返回 a pair<iterator, bool>,bool如果我们插入了一个新元素,则为 true,如果该元素已经在集合中,则为 false。
这是否是好的代码是有争议的。使用标准算法阅读代码时的一个普遍期望是 lambda 不会改变事物,并且这个 lambda 会numbers在其过程中发生变异。
如果你想保持find_duplicate函数的签名不变,你仍然可以这样做:
int find_duplicate(const vector<int> &v)
{
unordered_set<int> numbers;
auto it = std::find_if(v.begin(), v.end(),
[&](int num) { return !numbers.insert(num).second; });
return it == v.end() ? -1 : *it;
}
- I'd be inclined to put the `unordered_set` into the predicate: `[numbers = std::unordered_set<int>()](int num) mutable { ... }`: it doesn't have any business outside the predicate. A potential caveat is that the standard library doesn't make any promise on how the predicate gets copied...