http://www.careercup.com/question?id=14099679
Design an algorithm that, given a list of n elements in an array, finds all the elements that appear more than n/3 times in the list. The algorithm should run in linear time ( n >=0 )
You are expected to use comparisons and achieve linear time. No hashing/excessive space/ and don't use standard linear time deterministic selection algo
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
typedef map<int, int> Map;
Map findOverNth(int arr[], int size, int n);
int main()
{
//int arr[] = {5,6,7,8, 10, 10, 10,10,10,10, 4,4, 4, 4,4,1, 1,1,1};
int arr[] = {5,6,7,8, 10, 4,4, 4, 4,1, 1,1};
map<int, int>::iterator it;
int size = sizeof(arr) / sizeof(int);
Map map_result(findOverNth(arr, size, 3));
for(it = map_result.begin(); it != map_result.end(); it++)
{
cout<<(*it).first<<endl;
}
return 0;
}
Map findOverNth(int arr[], int size, int n)
{
Map a_map, result_map;
pair<map<int, int>::iterator, bool> insert_suc;
map<int, int>::iterator it;
for(int i = 0; i < size; i++)
{
if(a_map.size() < n)
{
it = a_map.find(arr[i]);
if(it != a_map.end())
{
(*it).second++;
}
else
{
a_map.insert(pair<int, int>(arr[i], 1));
}
}
if(a_map.size() == n)
{
for(it = a_map.begin(); it != a_map.end();)
{
(*it).second--;
if((*it).second == 0)
{
a_map.erase(it++);
}
else
it++;
}
}
}
result_map = a_map;
for(it = result_map.begin(); it != result_map.end(); it++)
{
(*it).second = 0;
}
for(int i = 0; i < size; i++)
{
it = result_map.find(arr[i]);
if(it != result_map.end())
{
(*it).second++;
}
}
for(it = result_map.begin(); it != result_map.end();)
{
if((*it).second * 3 < size)
result_map.erase(it++);
else
it++;
}
return result_map;
}
/*
#include <iostream>
#include <map>
#include <algorithm>
typedef std::map<int, int> Map;
Map findOverNth(int arr[], int size, int n)
{
Map ret_map;
typedef Map::value_type Elem; //pair<CONST int, int>
int total = 0;
std::for_each(arr, arr + size, [&, n](int val)
{
auto ret_pair = ret_map.insert(Elem(val, 0));
++(*ret_pair.first).second; ++ total;
if (ret_map.size() == n)
for (auto iter = ret_map.begin(); iter != ret_map.end(); )
{
--(*iter).second; -- total;
if ((*iter).second == 0)
ret_map.erase(iter++);
else
iter++;
}
});
std::for_each(ret_map.begin(), ret_map.end(), [](Elem &elem) {elem.second = 0;});
std::for_each(arr, arr + size, [&ret_map](int val) {if (ret_map.find(val) != ret_map.end()) ret_map[val] ++;});
for (auto iter = ret_map.begin(); iter != ret_map.end(); )
{
if ((*iter).second <= size / n)
ret_map.erase(iter++);
else
iter++;
}
return ret_map;
}
using namespace std;
int main()
{
//int arr[] = {5,6,7,8, 10, 4,4, 4, 4,1, 1,1};
int arr[] = {5,6,7,8, 10, 10, 10,10,10,10, 4,4, 4, 4,4,1, 1,1,1};
auto a_map = findOverNth(arr, sizeof(arr)/sizeof(int), 4);
cout<<sizeof(arr)/sizeof(int)<<endl;
//cout<<a_map.size()<<endl;
for each(auto elem in a_map)
{
cout<<elem.first<<" "<<elem.second<<endl;
}
}
*/
顺便讲讲map的功能。
这里红色标注的代码是一段正确的代码,但是看起来有些奇怪。
一开始的时候我是这样写的代码:
map<string,int> theMap;
// add something to theMap...
for(auto iter1 = theMap.begin(); iter1 != theMap.end(); ++iter1)
{
if(iter1->second == xxx)
{
theMap.erase(iter1); //#1 erase the element ??!!
}
}
这样程序肯定是会有bug的,因为erase了iter1的时候,这个指针就无效了,在对它进行任何的操作都会产生问题,可能是一个无法预知的bug或者崩溃。
所以要写成:
for(auto iter1 = theMap.begin(); iter1 != theMap.end(); )
{
if(iter1->second == xxx)
{
theMap.erase(iter1++); //#1
}else
{
++iter1;
}
}
好了,其他关于map的用法,查看STL的API,这里只mark一个这样的错误。后续想研究一下map背后的红黑树,当时学数据结构的时候没有学啊~