【问题标题】:counting duplicates in c++在 C++ 中计算重复项
【发布时间】:2016-09-24 22:58:32
【问题描述】:

假设我有一个整数数组 {100, 80, 90, 100, 80, 60}

所以我想计算这些重复项并将这些计数器保存以备后用。 因为每个重复的数字都应该除以计数器

like 100 被复制了 2 次,所以它们应该是 50 个。

为了查找重复项,我使用了排序。

std::sort(array, array + number);
for(int i = 0; i < number; i++) {
  if(array[i] == array[i+1])
    counter++;
}

并且我尝试制作计数器数组以将它们保存在每个数组中。但它没有用。请给我一些更好的主意。

【问题讨论】:

  • 正如所写,array[i+1] 中的索引超出了数组的顶部。将循环更改为仅运行到i &lt; number - 1。这不会解决计数问题,因为代码会计算所有重复项,而不是单独计算每个重复项。
  • 您要计算每个重复项(例如 100:2 和 80:2)吗?
  • 解决这些问题最经典的方法是二叉树,如果数量足够随机,否则为平衡二叉树。其他哈希表。
  • 是的,所以我想将每个 100 更改为 50 @Christophe
  • 数组中的ints 是否被限制在一个范围内?我的意思是,举个例子,你不知道有多少和什么,但你知道它们在[N,M[ 的范围内。是这样吗?

标签: c++ duplicates


【解决方案1】:

方法 1

最简单的方法是不对数组进行排序,而是增加地图的元素:

unordered_map<int, size_t> count;  // holds count of each encountered number 
for (int i=0; i<number; i++)        
    count[array[i]]++;             // magic ! 

然后您可以处理地图的内容:

for (auto &e:count)                // display the result 
    cout << e.first <<" : "<<e.second<< "-> "<<e.first/e.second<<endl; 

如果需要,通过从地图中重新删除它们或在处理过程中忽略它来过滤掉非重复项。

方法 2

如果您不允许使用地图,那么您必须详细说明您的计数循环,以便为每个新数字重新开始计数,并且如果超过两个也能够处理连续重复:

...
for(int i = 0; i < number; i+=counter) {
    for (counter=1; i+counter<number && array[i+counter]==array[i]; ) 
        counter++;       // count consecutives dups
    if (counter>1) {     // if more than one, process the dups.  
        cout << "dup: " << array[i] << " "<<counter<<endl;   
    }
}

如果您需要存储对以在第二步中处理它们,则需要存储一对(最好在向量中,但如果需要在数组中):

pair<int, size_t> result[number];  // a vector would be preferable
int nres=0; 
... 
    if (counter>1) {     // if more than one, process the dups.  
        // cout << "dup: " << array[i] << " "<<counter<<endl; 
        result[nres++] = make_pair(array[i], counter);  
    }
...

Online demo for both approaches

【讨论】:

  • 天哪,非常感谢!!我一直在为此苦苦挣扎,我不知道如何使用地图,但这对我真的很有帮助:)
  • 抱歉再次询问。但我一直在想,我不知道如何通过重复的计数器来划分每个重复项,例如{10,10,6,6,7} => {5,5,3,3,7} 不使用地图?
  • 如果您可以使用地图,请毫无疑问地使用它。如果不允许(家庭作业?),那么您禁止将一对存储在向量中(见上文),或存储在包含数字和计数的结构的向量中(即手工制作的对),或使用 2 个向量:一个用于找到的重复项,一个用于相应的计数。
【解决方案2】:

使用std::map&lt;int,int&gt;std::unordered_map 计算出现次数。

然后遍历映射并用键除以原始值(计数器)替换每个值。

最后遍历原始数组并将每个数字替换为其映射值。

如果你使用std::unordered_map,算法是 O(n)。你原来的 O(n log n) 因为涉及排序。

【讨论】:

  • 但问题是这些数字在结构中。我可以将 map 与 struct 一起使用吗?
  • @Hmmmmm:您可以使用结构映射,但我认为从结构中提取整数更有意义。
  • @Hmmmmm:地图不需要包含结构 - 只是整数。当你第一次遍历数组时,你把整数拉出来(counter[ array[i].int_member ] ++;)。当你第二次通过时,你只需更新成员:array[i].int_member = counter_map[ array[i].int_member ];)
  • @Hmmmmm 或者您可以为您的结构专门化std::hash 并将您的结构的operator== 实现为std::unordered_map 按预期工作
【解决方案3】:

如果你想直接改变数组编号,你可以这样操作:

for (int i = 0, counter = 1; i < number; i++) {
    if (array[i] == array[i + 1])
        counter++;
    else { //when finished counting duplicates
        for (int j = counter; j > 0; j--) //adjustment for subscripts
            array[i - j + 1] /= counter; //change the values stored in array
        counter = 1;//reinitialize array to 1
    }
}

您存储在数组中的排序值已经被相应的计数器除过一次。

【讨论】:

    【解决方案4】:

    如果您被允许修改序列,这里是替换元素的算法:

    const auto begin = std::begin( data );
    const auto end = std::end( data );
    std::sort( begin, end );
    for( auto it = begin; it != end; ) {
        auto next = std::upper_bound( std::next( it ), end, *it );
        auto newval = *it / std::distance( it, next );
        std::fill( it, next, newval );
        it = next;
    }
    

    ideone 上的演示

    修改PS使其也可以用数组编译。

    【讨论】:

    • 这些数字在结构中。如何访问结构成员?
    • @Hmmmmm 很简单。您在提供适当信息的地方创建新问题。
    猜你喜欢
    • 2021-08-29
    • 2013-07-24
    • 2012-03-24
    • 1970-01-01
    • 2014-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    相关资源
    最近更新 更多