我有一个巨大的int数组,我需要找到Mode of,
我见过一些使用2 for
循环(一个嵌套)的方法,这似乎是不必要的。
我能想到只用一个循环找到模式的唯一方法就是使用Map
s:
int[] elements = new int[]{....numbers...};
Map<Integer,Integer> map = new .....Map Type....;
for(int number : elements){
if(map.containsKey(Integer.valueOf(number))){
map.put(Integer.valueOf(number),map.get(Integer.valueOf(number))+1);
}else{
map.put(Integer.valueOf(number),1);
}
}
我不确定使用地图会带来什么样的速度优势。 有更好的方法吗?
答案 0 :(得分:5)
如果使用哈希映射,算法的运行时复杂度应为O(n):您访问n个元素中的每一个,并且通常假设HashMap查找和写入为O(1)。所以总共得到O(n * 1)即O(n)。如果使用树形图,则会得到O(n log n)。
与两个嵌套循环(听起来像O(n²))相比,速度提升从二次变为线性,这是非常好的:对于1000个元素,你执行1000“步”而不是1,000,000。
P.S。变得比线性更好在这里可能很难 - 无法想象一种计算方法而不至少访问每个元素一次。
答案 1 :(得分:5)
正如Stefan Haustein已经写过的那样,使用地图的复杂性比使用2 for循环要低得多。
如果您知道阵列中存储的数字范围,还可以进行一项进一步的改进或专业化。例如,如果计算的颜色范围为0-255,则不必使用地图,而是可以使用简单的数组。
int[] elements = new int[]{....numbers...};
int[] histogram = new int[256]; // 255 = highest possible value in elements
for(int number : elements){
++histogram[number];
}
使用地图是一种更通用的方式。您可以将地图视为具有更复杂索引功能的数组。因此,在正常数组中,数字为array pointer + index
,而在地图中,这是使用线性哈希函数计算的。
答案 2 :(得分:0)
没有算法比O(n)更快(查看big-o notation的维基百科页面)。至少,不一致(跨所有可能的输入)。这并不意味着它不能更快 - 只是超过一定的问题大小,任何更快的速度都不能继续增加速度差超过一个(可能很小的)线性因子。
这是因为,无论您检查元素的顺序如何,给定一个与获胜者“几乎平衡”的数组,您检查的最后一个元素可能会成为决胜局。给我任何不查看所有元素的算法,我可以编写一个输入数组,使其返回不正确的结果。因此,您必须至少检查一次所有这些:O(n)复杂性。
Hashmaps具有O(1)的一般插入和查找复杂性 - 也就是说,平均而言,无论数据的大小如何,它们都会花费一个恒定的时间来完成它们的工作。请注意,此常量时间比数组更新/查找大几倍(请参阅 TwoThe 的答案)。因此,除了常量(根据hashmap实现,机器,VM等等而有所不同)之外,您所获得的代码的速度要快得多。如果您确实需要10%的额外性能,那么就尽可能地将硬件/软件/输入数据建立在预期部署的基准上并优化 。