【问题标题】:How to find duplicate elements' index in C++?如何在 C++ 中查找重复元素的索引?
【发布时间】:2016-12-29 00:38:13
【问题描述】:

C++ 中是否有任何 STL 函数可以让我找到数组中所有重复项的索引?

例如:

int array[] = {1,1,2,3,4};

应该返回 0,1

【问题讨论】:

  • 进行了厚颜无耻的编辑;大概你想要一个整数数组,而不是一个指向整数的数组和一卡车的 UB?
  • 我想你可以用std::sortstd::adjacent_find 和一个循环来做到这一点。
  • 改变数组可以吗?临时更改阵列可以吗?创建临时数组可以吗?如果更改正常,请参阅@NathanOlivier 的评论。
  • @NathanOliver 但是任何带有排序的解决方案都会丢失原始索引。
  • 数组中的类型总是integer(还是内置类型)?这可能会影响算法的设计选择

标签: c++ arrays stl


【解决方案1】:

我认为没有现成的 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(N^2)。不到那个时间就不能完成吗?
  • 嗯,这是 O(n**2),而排序可能更接近 O(nlogn)。
  • @Raghav:我想不出一种“枢轴”式的方法可以给你 O(N log N)。
  • 嗯,人们普遍认为快速排序是 nlogn ... :) 但这只是 O() 表示法,如果 OP 对现实世界的性能感兴趣,他应该发布真正的数据约束和结构,因为对于有利的 n,精益 n**2 仍然比脏 nlogn 更快。
【解决方案2】:

高效地,您可以使用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 是该元素在数组中的索引。

  • 对于每个项目,a 在数组中具有索引i

    • 如果adup中以k的形式存在,则查找kv
    • 如果存在,
      • i 插入rtn
      • v 插入rtn
    • 否则,将ai 作为kv 添加到dup
  • 返回rtn

查看完整示例:Live on 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,您不需要对结果数组进行排序。
【解决方案3】:

我的两分钱。虽然不太确定这个的大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;
}

Try it online!

【讨论】:

    猜你喜欢
    • 2022-01-18
    • 1970-01-01
    • 2019-12-31
    • 1970-01-01
    • 2014-11-10
    • 2017-04-15
    • 1970-01-01
    • 2019-11-30
    相关资源
    最近更新 更多