在Java中,我需要一种算法来查找最大值。整数集合中出现的次数。例如,如果我的集合为[2,4,3,2,2,1,4,2,2]
,则算法需要输出5,因为2是最常出现的整数,它出现5次。考虑它就像找到整数集的直方图的峰值一样。
面临的挑战是,我必须逐个为多组整数做一遍,因此需要高效。另外,我不知道哪些元素大部分会出现在集合中。这完全是随机的。
我考虑过将这些值的值放入一个数组中,对它进行排序,然后迭代数组,计算数字的连续出现次数并确定计数的最大值,但我猜这将需要很长时间。是否有任何库或算法可以帮助我有效地做到这一点?
答案 0 :(得分:3)
排序有什么问题?那是 O(n log n),这一点都不错。任何更好的解决方案都需要有关输入集的更多信息(可能涉及的数字的上限)或涉及Map<Integer, Integer>
或等效的内容。
答案 1 :(得分:3)
我会使用以下逻辑将集合插入Map数据结构:
您可以使用Java中的两个地图 - HashMap和TreeMap - 这些在下面进行比较:
HashMap与TreeMap
如果您愿意,可以跳过详细说明直接跳转到摘要。
HashMap是一个存储数组中键值对的Map。用于密钥k的索引是:
有时两个完全不同的键最终会在同一个索引处。为了解决这个问题,数组中的每个位置实际上都是一个链表,这意味着每个查询总是必须遍历链表并使用k.equals(other)方法检查是否相等。最糟糕的情况是,所有密钥都存储在同一位置,HashMap成为未编制索引的列表。
随着HashMap获得更多条目,这些冲突的可能性增加,结构的效率降低。要解决这个问题,当条目数达到临界点(由构造函数中的loadFactor参数确定)时,结构将调整大小:
正如您所看到的,如果有许多调整大小,这可能会变得相对昂贵。
如果您可以在开始之前以适当的大小预先分配HashMap,则可以解决此问题,例如map = new HashMap(input.size()* 1.5)。对于大型数据集,这可以大大减少内存流失。
因为键基本上随机定位在HashMap中,所以键迭代器将以随机顺序迭代它们。 Java确实提供了LinkedHashMap,它将按照插入键的顺序进行迭代。
HashMap的性能:
OTOH树形图将条目存储在平衡树中 - 动态结构随着键值对的增加而逐渐建立。 Insert取决于树的深度(log(tree.size()),但是可以预测 - 与HashMap不同,没有线程,也没有性能下降的边缘条件。
给定分布均匀的HashMap,每次插入和查找都会更加昂贵。
此外,为了在树中插入密钥,每个密钥必须与每个其他密钥相当,需要来自Comparable接口的k.compare(other)方法。显然,鉴于问题是关于整数,这不是问题。
TreeMap的性能:
<强>摘要强>
首先想法:数据集大小:
在这种特定情况下,关键因素是与整体数据集大小相比,预期的唯一整数数量是大还是小?
如果上面没有压倒性的观点,最后一点:
但是,如果性能很重要,唯一的决定方法是实现Map接口,然后 profile HashMap和TreeMap,看看哪种情况在你的情况下更好。 Premature optimization是邪恶的根源:)
答案 2 :(得分:2)
基本方法是对集合进行排序,然后只运行已排序的集合。 (这将在O(nLog(n)+ n)中完成,即O(nLog(n)))。
如果数字有界(例如,-10000,10000)并且集合包含大量整数,则可以使用查找表并计算每个元素。这将取O(n + 1)(O(n)用于计数,O(l)找到max元素)其中l是范围长度(在这种情况下为20001)。 如您所见,如果n&gt;&gt;然后,这将变为优于1的O(n),但是如果n <&lt;然后它是O(l),它是恒定的但足够大,使其无法使用。
上一个的另一个变体是使用HashTable而不是查找表。这将改善O(n)的复杂度,但是当n> 1时,不能保证快于2。 好消息是价值不必受限制。
我不是一个java,但如果你需要帮助编码这些,请告诉我。
答案 3 :(得分:1)
以下是程序的示例实现。它返回大多数频率的no,如果发现两个nos出现max maxncence,则返回较大的no。如果你想返回频率,那么将代码的最后一行改为“return mf”。
{public int mode(int[]a,int n)
{int i,j,f,mf=0,mv=a[0];
for(i=0;i<n;i++)
{f=0;
for(j=0;j<n;j++)
{if(a[i]==a[j])
{f++;
}
}
if(f>mf||f==mf && a[i]>mv)
{mf=f;
mv=a[i];
}
}
return mv;
}
}
答案 4 :(得分:1)
这只小狗工作(编辑以返回频率而不是数字):
public static int mostFrequent(int[] numbers) {
Map<Integer, AtomicInteger> map = new HashMap<Integer, AtomicInteger>() {
public AtomicInteger get(Object key) {
AtomicInteger value = super.get(key);
if (value == null) {
value = new AtomicInteger();
super.put((Integer) key, value);
}
return value;
}
};
for (int number : numbers)
map.get(number).incrementAndGet();
List<Entry<Integer, AtomicInteger>> entries = new ArrayList<Map.Entry<Integer, AtomicInteger>>(map.entrySet());
Collections.sort(entries, new Comparator<Entry<Integer, AtomicInteger>>() {
@Override
public int compare(Entry<Integer, AtomicInteger> o1, Entry<Integer, AtomicInteger> o2) {
return o2.getValue().get() - o1.getValue().get();
}
});
return entries.get(0).getValue().get(); // return the largest *frequency*
// Use this next line instead to return the most frequent *number*
// return entries.get(0).getKey();
}
选择AtomicInteger是为了避免每次增量都创建新对象,代码看起来更清晰。
匿名地图类用于集中“if null”代码
这是一个测试:
public static void main(String[] args) {
System.out.println(mostFrequent(new int[] { 2, 4, 3, 2, 2, 1, 4, 2, 2 }));
}
输出:
5
答案 5 :(得分:1)
因为它是一个整数集合,所以可以使用
注意:
答案 6 :(得分:0)
使用HashMap:
export const hideSnackBar = () => ({
type: SNACKBAR_HIDE
});