在C++中,有没有STL函数可以找到数组中所有重复元素的索引?
例如:
int array[] = {1,1,2,3,4};
应该返回 0,1。
为了高效地跟踪重复的索引,您可以使用 std::unordered_set
(用于唯一地跟踪重复的索引),并使用 std::unordered_map
(用于跟踪唯一数字及其索引)。
这样做的时间复杂度为 O(N * [O(1) + ... + O(1)])
...大约等于 O(N)
:
template<typename ForwardIterator>
std::vector<int> get_duplicate_indices(ForwardIterator first, ForwardIterator last){
std::unordered_set<int> rtn;
std::unordered_map<int, int> dup;
for(std::size_t i = 0; first != last; ++i, ++first){
auto iter_pair = dup.insert(std::make_pair(*first, i));
if(!iter_pair.second){
rtn.insert(iter_pair.first->second);
rtn.insert(i);
}
}
return {rtn.begin(), rtn.end()};
}
解释:
给定一个数组 A
rtn
。使用一个 KV(键值)映射,dup
;其中 k
是数组 A
中的一个元素,v
是该元素在数组中的索引。
对于数组中的每个具有索引 i
的项 a
:
k
等于a
并且属于dup
,则找到kv
i
插入到 rtn
中v
插入到 rtn
中a
和 i
作为kv
添加到 dup
中rtn
查看完整示例:在 Coliru 上实时演示。
输入为:
int array[] = {1,1,2,3,4};
我们的输出结果是:
1 0
再次提醒,
对于以下输入:
int array[] = {1, 1, 2, 3, 4, 1, 0, 0, 9};
7 0 5 1 6
set
而不是unordered_set
,这样您就不需要对结果数组进行排序。 - Marian Spanik我认为 STL 没有现成的方法可以做到这一点。以下是一个 O(N*N) 的解决方案:
int array[] = {1, 2, 3, 1, 4};
constexpr int size = 5; // ToDo - don't hardcode this.
bool duplicates[size] = {};
for (std::size_t i = 0; i < size; ++i){
if (!duplicates[i]){ /*No point in re-testing*/
for (std::size_t j = i + 1; j < size; ++j){
if (array[i] == array[j]){
duplicates[i] = duplicates[j] = true;
}
}
}
}
基于排序的方法可能对较长的数组更有效:但是您需要构建一个新位置 -> 旧位置的表格,以获取重复元素的索引。
这是我的一些想法。不太确定这个的大O时间复杂度,但是看起来像是O(N):
std::vector<std::size_t> findDuplicateIndices(std::vector<int> const & v)
{
std::vector<std::size_t> indices;
std::map<int, std::pair<int, std::size_t>> counts; // pair<amount, firstSeenPos>
for (std::size_t i = 0 ; i < v.size() ; ++i)
{
std::size_t const amount = ++counts[v[i]].first;
/**/ if (amount == 1) // First encounter, record the position
{
counts[v[i]].second = i;
continue;
}
else if (amount == 2) // Second encounter, add the first encountered position
indices.push_back(counts[v[i]].second);
indices.push_back(i);
}
return indices;
}
std::sort
、std::adjacent_find
和循环来完成这个任务。 - NathanOliver