假设我有一系列双打,如下所示:
Array[10] = {10, 10, 10, 3, 10, 10, 6, 10, 10, 9, 10}
我需要一个可以确定数组中MAJORTY投票的函数,在本例中为“10”,因为它是最常出现的数字... 当然,没有多数存在(他们是平等的)的情况,在这种情况下,我需要抛出异常...
任何线索?除了在数组上做一些非常讨厌的循环之外(对于每个索引,确定存在多少具有相同值的数量,在数组中存储计数,然后扫描计数数组中的最高数字,并且该位置的值是赢家等等......)
答案 0 :(得分:17)
使用Map<Integer, Integer>
应该很简单:
int mostFrequent(int... ary) {
Map<Integer, Integer> m = new HashMap<Integer, Integer>();
for (int a : ary) {
Integer freq = m.get(a);
m.put(a, (freq == null) ? 1 : freq + 1);
}
int max = -1;
int mostFrequent = -1;
for (Map.Entry<Integer, Integer> e : m.entrySet()) {
if (e.getValue() > max) {
mostFrequent = e.getKey();
max = e.getValue();
}
}
return mostFrequent;
}
答案 1 :(得分:5)
你的第一个问题是你有一个“双打数组”,因为浮点数据的相等性是有问题的(相同的数值可以用不同的位模式表示,等等)。如果您的双打事实上(如示例中)整数,则使用int
代替。另外,请仔细考虑如何定义哪些值相等以表示相同的投票。
至于确定多数投票,使用带有“投票ID”作为关键字的Map
和投票数作为值 - 然后最后遍历地图以找到最大值。
答案 2 :(得分:4)
首先按快速排序对数组进行排序,然后扫描并计算多数 - O(n ln n)。如果提前知道元素的范围,比如在{1,k}之间,则可以使用计数排序,它将在O(n + k)中运行。
稍微改进一下,当你扫描已排序的数组时,如果你发现有超过n / 2次出现的值就完成了。
答案 3 :(得分:4)
对于一系列双打,这可能并不容易,因为对双打的平等比较是非常有问题的。 如果您可以使用整数,可以执行以下操作:
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
for(int element: Array)
{
Integer frequency = map.get(element);
map.put(element, (frequency != null) ? frequency + 1 : 1);
}
int mostFrequentItem = 0;
int[] maxFrequencies = new int[2];
maxFrequencies[0] = Integer.MIN_VALUE;
for(Entry<Integer, Integer> entry: map.entrySet())
{
if(entry.getValue()>= maxFrequencies[0])
{
mostFrequentItem = entry.getKey();
maxFrequencies[1] = maxFrequencies[0];
maxFrequencies[0] = entry.getValue();
}
}
if(maxFrequencies[1] == maxFrequencies[0])
throw new Exception();//insert whatever exception seems appropriate
return mostFrequentItem
这将具有O(n)性能,因此它在渐近性能行为中应该是非常优化的。如果您的双打不是计算结果而是来自其他来源,那么如果您可以确定基本相同的值将被平等地表示,那么您可能会使用相同的方法来实现双打,但是我会仍然建议小心这是真的。
编辑:评论中建议的一些性能改进以及支持检查不明确的案例
答案 4 :(得分:2)
正如@Grizzly指出的那样,从计算的角度看,双打是有问题的。我还建议从问题域的角度来看它们没有意义;多数投票双打没有任何意义!
因此,我们假设10
和6
等等是人们投票的事物的整数标识符。让我们假设您知道用户可以对从0
到10
的任何值进行投票。
int[] votes = ...
int[] voteCounts = new int[11]; // 11 could be calculated ...
for (int vote : votes) {
voteCounts[vote]++;
}
int majority = (votes.length + 1) / 2;
for (int i = 0; i < voteCounts.length; i++) {
if (voteCounts[i] >= majority) {
return i; // the winner!
}
}
throw new NoClearMajorityException(...);
此算法在时间上为O(N)
,在空间中为O(M)
,其中M是最大的标识符。问题是如果标识符是整数,它只能起作用(如所写的那样)。
答案 5 :(得分:2)
我刚用新的Java 8创建了这么漂亮的小解决方案:
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class MostCommonObject {
public static void main(String[] args) {
System.out.println(mostCommonObject(new Integer[] { -4, 1, -2, 3, 1, -2, 3, 1 }));
}
public static <T> T mostCommonObject(T[] array) {
return mostCommonObject(Arrays.asList(array));
}
public static <T> T mostCommonObject(Collection<T> collection) {
Map<T, Integer> map = new HashMap<>();
collection.forEach(t -> map.compute(t, (k, i) -> i == null ? 1 : i + 1));
return map.entrySet().stream().max((e1, e2) -> Integer.compare(e1.getValue(), e2.getValue())).get().getKey();
}
}
答案 6 :(得分:1)
试试这个,
Integer[] array=new Integer[]{10, 10, 10, 3, 10, 10, 6, 10, 10, 9, 10};
List<Integer> demoList=new ArrayList<Integer>(Arrays.asList(array));
Set<Integer> set=new HashSet<Integer>(demoList);
Map<Integer,Integer> myMap=new HashMap<Integer, Integer>();
for (Integer integer : set)
{
int count=Collections.frequency(demoList, integer);
myMap.put(count, integer);
}
int maxOccurance=myMap.get(Collections.max(myMap.keySet()));
答案 7 :(得分:0)
您可以这样做:将您的数组转换为列表并对其进行排序。选择第一个索引,并对值调用lastIndexOf(obj)。对您遇到的每个新值执行此操作,计算值的范围并将最大范围的结果存储在变量中。
答案 8 :(得分:0)
您真正想要做的是计算给定集合中某些项目的出现次数。事实上,这是在不到一天前提出的,你可能想看看这个very relevant question。