我的一位同事在接受采访时被问到了问题。
给定一个存储unsigned int的巨大数组。数组长度为100000000.找到计算数组中唯一元素数的有效方法。
例如,{2,34,5,6,7,2,2,5,1,34,5}
O / p:2的计数是3,34的计数是2,依此类推。
执行此操作的有效算法是什么?我认为首先字典/哈希将是一个选项,但由于数组非常大,它是无效的。有没有办法做到这一点?
谢谢, 乔塔
答案 0 :(得分:10)
堆排序是O(nlogn)和就地。处理大型数据集时就地是必要的。排序后,您可以通过数组进行一次计算,计算每个值的出现次数。因为数组已经排序,所以一旦值发生变化,您就会知道您已经看到所有出现的前一个值。
答案 1 :(得分:7)
许多其他海报建议对数据进行排序,然后查找相邻值的数量,但是没有人提到使用基数排序来使运行时变为O(n lg U)(其中U是最大值)数组)而不是O(n lg n)。由于lg U = O(lg n),假设整数占用一个机器字,这种方法渐近比heapsort快。
非比较分类在面试中总是很有趣。 : - )
答案 2 :(得分:2)
对其进行排序,然后从头开始扫描以确定每个项目的计数。
此方法不需要额外的存储空间,可以在O(n log n)时间内完成(对于排序)。
答案 3 :(得分:1)
如果int值的范围有限,那么您可以分配一个数组,用于计算每个可能值的出现次数。然后你只需遍历你的巨大阵列并增加计数器。
foreach x in huge_array {
counter[x]++;
}
因此,您可以在线性时间(O(n))中找到解决方案,但代价是内存消耗。也就是说,如果你的整数跨越32位整数允许的整个范围,你需要分配一个4G整数的数组,这是不切实际的......
答案 4 :(得分:1)
如何使用BloomFilter impl:如http://code.google.com/p/java-bloomfilter/ 首先执行bloom.contains(element)如果为true,则返回false bloom.add(element)。
最后计算添加的元素数量。 Bloomfilter需要大约。 250mb内存,每个元素10位存储100000000个元素。
问题是BloomFilters中可能出现误报,并且只能通过增加每个元素的位数来最小化。这可以通过两个需要同意的具有不同散列的BloomFilter来解决。
答案 5 :(得分:0)
在这种情况下散列并不合适。对于迭代数组,成本大约为O(N)
(O(N)
,对于哈希表迭代,成本约为O(N)
。由于您需要O(N)
来检查每个元素,因此复杂性很高。
答案 6 :(得分:0)
排序是一个好主意。但是,排序类型取决于可能值的范围。对于小范围计数排序会很好。在处理如此大的阵列时,使用多个核心会很有效 - 基数排序可能会很好。
答案 7 :(得分:-2)
查看它的变体,它可能会帮助您找到“否”。不同的元素。
#include <bits/stdc++.h>
using namespace std;
#define ll long long int
#define ump unordered_map
void file_i_o()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
}
int main() {
file_i_o();
ll t;
cin>>t;
while(t--)
{
int n,q;
cin>>n>>q;
ump<int,int> num;
int x;
int arr[n+1];
int a,b;
for(int i=1;i<=n;i++)
{
cin>>x;
arr[i]=x;
num[x]++;
}
for(int i=0;i<q;i++)
{
cin>>a>>b;
num[arr[a]]--;
if((num[arr[a]])==0)
{ num.erase(arr[a]); }
arr[a]=b;
num[b]++;
cout<<num.size()<<"\n";
}
}
return 0;
}