给定一个整数数组,我需要找到最多次出现的数字。 我编写了如下算法。
使用地图存储发生的次数和次数。
map<int, int>
键:代表数字
value:表示密钥发生的次数。- 扫描输入数组并使用编号和出现次数更新地图。
- 从头到尾迭代地图。找到钥匙 哪个最大值存在。这个 key成为发生的数字 最多次。
醇>
我实现了如下算法。
#include <iostream>
#include <map>
using namespace std;
int main()
{
int a[10] = {1,2,3,2,1,3,2,4,1,1}; //Input array: hardcoded for testing
map<int, int> m;
for(int i=0;i<10;i++)
{
m[a[i]]++; //Increment the value of key for counting occurances
}
int mostNumTimes = 0;
int number = -999; //-999 represents invalid number
map<int,int>::iterator it = m.begin();
for( ;it != m.end(); it++) //Find the number which occurred
{ //most number of times
if(it->second > mostNumTimes)
{
mostNumTimes = it->second;
number = it->first;
}
}
if(number != -999) //Print number and number of times it occurred
{
cout<<"Number: "<<number<<endl;
cout<<"Number of times occured: "<<mostNumTimes<<endl;
}
else
{
cout<<"Input array is empty"<<endl;
}
return 0;
}
输出:
数量:1
发生的次数:4
问题:有没有最佳方法? 最后,我正在迭代整个地图,因为我找不到任何成员函数来查找其值在地图中最高的键。我可以避免迭代所有键吗?
注意:我没有考虑多个号码是否发生相同的次数。我发现第一个出现次数最多的数字。
答案 0 :(得分:8)
您可以在迭代值时保持当前最大值(count和int值)。在地图中的每个增量上,您可以更新值,这样就不必在最后进行迭代。
map<int, int> m;
int currentMax = -999;
int maxCount = 0;
for(int i=0;i<10;i++)
{
int updated = m[a[i]]++; //Increment the value of key for counting occurances
updated++; // due to post increment
if (maxCount < updated) {
maxCount = updated;
currentMax = i;
}
}
因为这是一项有趣的练习,我们似乎都假设地图迭代很便宜。虽然迭代地图也是O(N),但它比迭代矢量或数组要昂贵得多。那么什么更便宜,迭代一个可能缩小的大小的地图,或做一个非常基本的检查,将以某个百分比触发两个任务?假设您更改为使用无序映射,那么您的解决方案和此解决方案都是O(N)。现在你不是,所以每个插入都是log(n),实际上我认为切换到无序地图将是你最大的收获。
答案 1 :(得分:4)
你的算法非常好。它实际上是O(N Log N),因为您正在进行N std :: map(基于树的地图)插入(每个Log N)。这决定了算法的时间复杂度,因为第二阶段是线性的。
改进将是使用哈希映射,为您提供整体的线性算法。
答案 2 :(得分:2)
对数组进行排序,以便...
{1,1,1,1,2,2,2,3,3,4,4}
然后有一个currentValue变量,当值不匹配时设置它,当它设置时,递增计数...即(伪代码)
currentValue = 0;
currentCount = 0;
maxValue = 0;
maxCount = 0;
for(int value in array) {
if(currentValue == value) {
currentCount++;
} else {
// is this greater than max count
if(currentCount > maxCount) {
maxCount = currentCount;
maxValue = currentValue;
}
// reset values
currentValue = value;
currentCount = 0;
}
}
现在您拥有maxValue中出现次数最多的值以及maxCount中出现的次数。
答案 3 :(得分:0)
首先,你应该摆脱无效的数字-999。在继续之前,请先询问map.empty()。
然后,我认为增加地图中之前不存在的元素是无效的。我假设使用unitialized(random)值创建了一个新成员,因为int没有默认构造函数。
您可以做其他事情:
map<int, int>::iterator it = m.find(i);
if (it != m.end())
m.second++;
if (m.second > mostTimes) {
// reset mostTimes and maxNumber = m.first here
}
} else {
m[i] = 1;
}
此操作为O(n),因此具有相同的时间复杂度类,再次迭代地图以找到最大元素(在最坏的情况下,输入中的所有数字都不同,并且地图具有相同的数量成员n比输入数组)。但不同之处在于,大多数Time和maxNumbers可能会被覆盖很多次,并且可能会发生它们不适合CPU寄存器并且会发生大量RAM访问。因此,事后进行迭代可能会更快。
答案 4 :(得分:0)
需要线性迭代(正如人们已经提到的那样),但是给定顺序并不重要,你可以折叠数组吗?这样做可以为相同的元素保存两个地图更新,即
int i = 0;
int j = sizeof(a)/sizeof(int);
for(;i < j;i++, j--)
{
if (a[i] == a[j])
{
update<map_t, 2>(m, a[i]);
}
else
{
update<map_t, 1>(m, a[i]);
update<map_t, 1>(m, a[j]);
}
}
// if array size is odd...
if (i == j)
update<map_t, 1>(m, a[i]);
这里update是一个简单的函数,因为我懒得输入相同的代码......
template <typename M, int DEF>
void update(M& m, int v)
{
typename M::iterator it = m.find(v);
if (it != m.end())
it->second += DEF;
else
{
m.insert(pair<int, int>(v, DEF));
}
}
其他一切都保持不变,即你的代码很好,只有轻微的改进......