如何打印数组中出现最多的前5个数字?

kt06eoxx  于 2022-09-18  发布在  Java
关注(0)|答案(5)|浏览(265)

我应该“编写一个方法,打印出数组中最常出现的前5个数字,以及每个数字的出现次数”我有一个方法打印出一个数组中每个条目的出现次数,我创建了另一个方法来打印数组中前5个出现次数。我能够以降序正确显示这些值,但我很难获得相同的键。例如,我的输出是“2发生:5次3发生:4次4发生:3次5发生:3倍6发生:2次”当它应该是“3发生:5倍9发生:4倍6发生3倍7发生3倍5发生2次”我如何修复我的方法以获得预期的输出?

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Random;

public class HW4 {

    public static void main(String[] args) {
        int[] a = getRandom(20, 1, 10);
        System.out.println(Arrays.toString(a));
        System.out.println();
        occurrence(a);
        System.out.println();
        top5(a);

    }

    public static int[] getRandom(int n, int low, int high) {

        long seed = 0;
        Random random = new Random(seed);
        random.setSeed(seed);

        int[] result = new int[n];

        for (int i = 0; i < n; i++)

            result[i] = random.nextInt(high - low) + low;

        return result;

    }

    public static void occurrence(int[] x) {
        HashMap<Integer, Integer> occurrences = new HashMap<>();
        for (int key : x) {
            if (occurrences.containsKey(key)) {
                occurrences.put(key, occurrences.get(key) + 1);
            } else {
                occurrences.put(key, 1);
            }
        }
        for (int key : occurrences.keySet()) {
            System.out.println(key + " occurs: " + occurrences.get(key) + " times");
        }
    }

    public static void top5(int[] arr) {
        HashMap<Integer, Integer> lookup = new HashMap<Integer, Integer>();
        for (int key : arr) {
            if (lookup.containsKey(key)) {
                lookup.put(key, lookup.get(key) + 1);
            } else {
                lookup.put(key, 1);
            }
        }
        ArrayList<Integer> keys = new ArrayList<>(lookup.keySet());
        ArrayList<Integer> values = new ArrayList<>(lookup.values());
        for (int i = 0; i < 5; i++) {
            Collections.sort(values, Collections.reverseOrder());
            System.out.println(keys.get(i) + " occurs: " + values.get(i) + " times");
        }
    }
}
daolsyd0

daolsyd01#

public static void top5(int[] arr) {
    IntStream.of(arr).boxed()
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
            .entrySet().stream()
            .sorted((e1, e2) -> Long.compare(e2.getValue() , e1.getValue()))
            .limit(5)
            .forEach(e -> System.out.printf("%d occurs %d times%n", e.getKey(), e.getValue()));
}

前两行创建直方图,即将每个值Map到其出现次数的Map。下一行获取条目流,这些条目将在下一行中按其值(即出现次数)按相反顺序排序。您只需要5个元素,因此结果被限制为5个,在最后一行中,结果输出格式良好。

ar7v8xwq

ar7v8xwq2#

条目列表+排序

最简单的方法是使用HashMap计算阵列中每个数字的频率,正如您所做的那样。
然后将所有Map条目转储到列表中,并按列表排序。我们需要Comparator来执行此排序。为此,我们可以使用Java 8方法Map.Entry.comparingByValue()来获得比较器
并且作为最后一步,打印第一5元素。

public static void top5(int[] arr) {
    Map<Integer, Integer> lookup = new HashMap<>();
    for (int key : arr) {
        int value = lookup.get(key); // or lookup.merge(key, 1, Integer::sum); instead of these two lines
        lookup.put(key, value + 1);
    }

    List<Map.Entry<Integer, Integer>> sortedEntries = new ArrayList<>(lookup.entrySet());

    sortedEntries.sort(Map.Entry.<Integer, Integer>comparingByValue().reversed());

    for (int i = 0; i < 5; i++) {
        System.out.println(
            sortedEntries.get(i).getKey() + " occurs: " + 
            sortedEntries.get(i).getValue() + " times"
        );
    }
}

优先队列

更有效的方法是使用PriorityQueue,而不是对整个数据进行排序。
第一步保持不变-生成一个频率图
下一步是创建一个PriorityQueue,它将存储Map条目。为此,我们还需要一个比较器。
然后迭代条目集,尝试将每个条目提供给队列。如果队列的大小等于5,并且下一个条目大于队列中最低数值(这将是PriorityQueue的根元素的值),则需要删除队列的根元素。只要有空闲空间,就应将下一个条目添加到队列中(如果队列大小小于5)。
下面是它的实现方式:

public static void top5(int[] arr) {
    Map<Integer, Integer> lookup = new HashMap<>();
    for (int key : arr) {
        int value = lookup.get(key); // or lookup.merge(key, 1, Integer::sum); instead of these two lines
        lookup.put(key, value + 1);
    }

    Queue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>(
        Map.Entry.comparingByValue()
    );

    for (Map.Entry<Integer, Integer> entry: lookup.entrySet()) {
        if (queue.size() == 5 && queue.peek().getValue() < entry.getValue()) queue.poll();
        if (queue.size() < 5) queue.offer(entry)
    }

    while (!queue.isEmpty()) {
        Map.Entry<Integer, Integer> next = queue.poll();

        System.out.println(
            next.getKey() + " occurs: " +
            next.getValue() + " times"
        );
    }
}
ie3xauqp

ie3xauqp3#

如果您正在寻找使用Hashmap的方法,您可以这样做

public static void top5(int[] arr) {
        LinkedHashMap<Integer, Integer> lookup = new LinkedHashMap<>();
        for (int key : arr) {
            if (lookup.containsKey(key)) {
                lookup.put(key, lookup.get(key) + 1);
            } else {
                lookup.put(key, 1);
            }
        }
        Map<Integer, Integer> result = lookup.entrySet() /* sorts the linked_map by value */
                .stream()
                .sorted(Map.Entry.comparingByValue())
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        Map.Entry::getValue,
                        (oldValue, newValue) -> oldValue, LinkedHashMap::new));

        List<Integer> key_in_order
                = new ArrayList<Integer>(result.keySet());  // convert to list

        /* reverse the key because it was backward compared to what you want */
        Collections.reverse(key_in_order);

        for (int i = 0; i < 5; i++) {
            System.out.println("key : "+String.valueOf(key_in_order.get(i)) + " value : " + result.get(key_in_order.get(i)) );
        }
    }

对于java,结果通常需要非常大的函数lol。可能有一种更有效的方法,但这是我个人提出的

e1xvtsh3

e1xvtsh34#

一旦创建了事件Map,
1.您可以创建一个最大密钥堆。您可以在最大堆中传递比较器,以根据事件Map中的值进行比较。

PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a,b)->occurrences.get(b)-occurrences.get(a))

1.在此之后,您可以从maxHeap轮询5次

for(int i=0;i<5;i++){
  if(!maxHap.isEmpty()){
    System.out.println(maxHeap.poll());
  }
}

您可以更新top5函数,如下所示:

public static void top5(Map<Integer, Integer> occurrences) {
        PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a, b) -> occurrences.get(b) - occurrences.get(a));
        maxHeap.addAll(occurrences.keySet());
        System.out.println("top 5");
        for (int i = 0; i < 5; i++) {
            if (!maxHeap.isEmpty()) {
                System.out.println(maxHeap.peek() + "  occurs: " + occurrences.get(maxHeap.poll()) + " times");
            }
        }
    }
prdp8dxp

prdp8dxp5#

在这个答案中,我假设您至少有五个数字:

Integer top5[] = new Integer[5];
int length = 0;
int minimumIndex = 0;
for (Integer key : occurrences.keySet) {
    if (length < 5) { //we take the first five items whatever they are
        top5[length++] = key; //we assign key to top5[length] and increment length
        if (length === 5) { //The elements are filled, getting the index of the minimum
            minimumIndex = 0;
            for (int index = 1; index < 5; index++) {
                if (occurrences.get(top5[minimumIndex]).intValue() > occurrences.get(top5[index]).intValue()) minimumIndex = index;
            }
        }
    }
    } else { //buildup completed, need to compare all elements
        if (occurrences.get(key).intValue() > occurrences.get(top5[minimumIndex]).intValue()) {
            //We found a larger item than the fifth largest so far
            top5[minimumIndex] = key; //we replace it
            //we find the smallest number now
            minimumIndex = 0;
            for (int index = 1; index < 5; index++) {
                if (occurrences.get(top5[minimumIndex]).intValue() > occurrences.get(top5[index]).intValue()) minimumIndex = index;
            }
        }
    }
}
top5 = Arrays.sort(top5, Collections.reverseOrder());

如果这个答案看起来太复杂,那么您可以将minimumIndex的计算分离成一个单独的方法,并使用两次。否则,它应该很容易应用,特别是因为还添加了注解。

相关问题