Java 查找实数数组中每个元素频率的最快算法?

Java 查找实数数组中每个元素频率的最快算法?,java,arrays,algorithm,performance,Java,Arrays,Algorithm,Performance,问题是找到实数数组中每个元素的频率 double[] a = new double[n] int[] freq = new int[n] 我提出了两个解决方案: 第一个解决方案O(n^2): for(int i=0;ih3,…)。然后可以创建一个哈希表,其中元素x将被哈希为3个值:x-3/4delta,x,x+3/4delta。 这保证了以后检查相等值时,它将在放置元素的3个位置中至少有一个位置匹配 实现起来要复杂得多,但它应该可以工作。在数学问题6中可以找到它的变体。(只需确保查看第5版,第

问题是找到实数数组中每个元素的频率

double[] a = new double[n]
int[] freq = new int[n]
我提出了两个解决方案:

第一个解决方案O(n^2):

for(int i=0;i
第二种解决方案O(nlogn):

quickSort(a,0,a.length-1);
频率[j]=1;
对于(int i=0;i
这个问题有没有更快的算法(可能是O(n))呢?
提前感谢您提供的任何帮助。

首先,我要说的是,检查
double
s的身份不是一个好做法。有关详细信息,请参阅:。
您应该使用更稳健的
double
比较

现在,我们已经完成了,让我们面对你的问题。
您正在处理浮点数的变化

一般来说,在代数树计算模型下,它不能比
Omega(nlogn)
更好(本线程中的参考文献:)

但是,如果您打算坚持使用
双重
身份检查(请不要这样做),您可以使用更强大的模型和哈希表来实现
O(n)
解决方案,方法是维护基于元素的哈希表(实现为
HashMap
),完成后,扫描直方图并生成最大值的键。
(请不要这样做)


即使在处理浮点运算时,也有一种基于散列的复杂方法来实现
O(n)
time
。这是基于将元素添加到哈希表的多个条目中,并假设哈希函数将一系列元素
[x-delta/2,x+delta/2)
取到相同的哈希值(因此它是以块
[x1,x2)->h1[x2,x3)->h2进行哈希,[x3,x4)->h3,…
)。然后可以创建一个哈希表,其中元素
x
将被哈希为3个值:
x-3/4delta,x,x+3/4delta

这保证了以后检查相等值时,它将在放置元素的3个位置中至少有一个位置匹配

实现起来要复杂得多,但它应该可以工作。在数学问题6中可以找到它的变体。(只需确保查看第5版,第4版中的答案是错误的,并且在较新的版本中已修复)



另一方面,您不需要实现自己的排序。使用Trie将在相当长的线性时间内执行,因为插入将非常快(或与实数的顺序一样快)

如果你只需要频率,那么排序和计数肯定太慢了。你的朋友是trie:

如果您使用的是Trie,那么您将把每个整数转换成一个字符串(在Java中非常简单)。插入Trie的复杂性根据实现的不同略有不同,但通常与字符串的长度成正比

如果您需要Trie的实现,我建议您在这里查看Robert Sedgwick算法课程的实现:


您的双打已经被适当地四舍五入,并且您确信不会有错误需要担心,您可以使用如下哈希映射

Map<Double, Long> freqCount = DoubleStream.of(reals).boxed()
        .collect(Collectors.groupingBy(d -> d, Collectors.counting()));
Map freqCount=DoubleStream.of(reals).boxed()
.collect(Collectors.groupingBy(d->d,Collectors.counting());
这占用了相当多的内存,但是是O(n)

另一种方法是使用以下内容作为第一遍

NavigableMap<Double, Long> freqCount =  DoubleStream.of(reals).boxed()
        .collect(Collectors.groupingBy(d -> d, TreeMap::new, Collectors.counting()));
NavigableMap freqCount=DoubleStream.of(reals).boxed()
.collect(Collectors.groupingBy(d->d,TreeMap::new,Collectors.counting());

这将计算所有完全相同的值,并且您可以使用分组策略组合几乎相同但出于您的目的应视为相等的双值。这是O(N log N)

检查
double
s的标识不是一个好的做法。作为旁注,这是元素区分性问题,不存在O(n)代数树模型下的解决方案。如果你想坚持使用double的标识,你可以使用哈希表,但同样-这是一种不好的做法。@amit为什么在上述情况下使用哈希表是不好的做法?你可以将数组排序为O(n log n),然后读取数组以检测每个数组的频率(在比较实际值时允许稍有不同的epsilon)元素出现(它们现在是序列)O(n)表示O(n log n)的所有时间。@sAm yes.double上的哈希表容易出错。创建二叉树需要O(n log n)是的,被删掉了。我认为Trie和你要得到的线性一样接近,除非你使用散列映射。
Map<Double, Long> freqCount = DoubleStream.of(reals).boxed()
        .collect(Collectors.groupingBy(d -> d, Collectors.counting()));
NavigableMap<Double, Long> freqCount =  DoubleStream.of(reals).boxed()
        .collect(Collectors.groupingBy(d -> d, TreeMap::new, Collectors.counting()));