Java - подсчет самых распространенных элементов

Задача состоит в том, чтобы написать код, который считает наиболее распространенное число. Например A[1,2,4,4,4,5,6,7,4] было бы 4 с 4 на счет. Мне нужно, чтобы этот код был простым, потому что я просто пытался реализовать свой код от алгоритма и структуры данных до Java.

Моя идея была такая, но почему-то я никогда не достигаю последнего состояния.

public class countingNumbers{

     public static void main(String []args){
         System.out.print(counting(new int[]{1,1,1,2,3,4,4,4,4,5,6}));
     }

     public static int counting(int[] x){
         int memory = 0; 
         int counter = 0;
         int mostCommon = 0;
         for(int i = 0; i < x.length-1;i++){
             for(int j = i+1; j < x.length-1; j++){
                 if(x[i] == x[j]){
                     counter = counter +1;

                 }
                 else if(j == x.length-1 && counter >= memory){
                     mostCommon = x[i];
                     memory = counter;
                     counter = 0;


                 }
             }
         }
         return  mostCommon;
     }
}

-> Заранее спасибо за все ваши ответы, я ценю это. Я просто ищу логику, а не поток, API или что-то еще. Я попытался написать код от руки, и реализация в java предназначена только для меня, чтобы увидеть, сработал ли он, но, к сожалению, это не так.

Обновление - правильное решение заключается в следующем:

открытый класс countingNumbers {

 public static void main(String []args){
     System.out.print(counting(new int[]{1,2,2,2,6,2}));
 }

 public static int counting(int[] x){
     int memory = 0; 
     int counter = 1;
     int mostCommon = 0;
     for(int i = 0; i < x.length;i++){
         for(int j = i+1; j <= x.length-1; j++){
             if(x[i] == x[j]){
                 counter = counter + 1;

             }
             if(j == x.length-1 && counter >= memory){
                 mostCommon = x[i];
                 memory = counter;
                 counter = 1;


             }
         }counter = 1;
     } return memory;


 }

}

4 ответа

Я бы поточил массив и собрал его на карту, подсчитывающую вхождения каждого элемента, а затем просто вернул тот, который имел наибольшее количество:

/**
 * @return the element that appears most in the array.
 * If two or more elements appear the same number of times, one of them is returned.
 * @throws IllegalArgumentException If the array is empty
 */
public static int counting(int[] x){
    return Arrays.stream(x)
                 .boxed()
                 .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
                 .entrySet()
                 .stream()
                 .max(Map.Entry.comparingByValue())
                 .map(Map.Entry::getKey)
                 .orElseThrow(() -> new IllegalArgumentException("x must not be empty"));
}

Если вы хорошо разбираетесь в Stream API или просто для образовательных целей, есть потоковое решение с groupingBy:

Integer[] arr = {1, 1, 1, 2, 3, 4, 4, 4, 4, 5, 6};

Map<Integer, Long> map = Arrays.stream(arr)
        .collect(Collectors.groupingBy(o -> o, Collectors.counting()));

Integer common = map.entrySet().stream()
        .max(Comparator.comparingLong(Map.Entry::getValue))
        .map(Map.Entry::getKey).get();

System.out.println(common);

Обновление: если поток не подходит для вас:

Это может быть сделано foor-loop но все же это довольно удобно использовать Map Вот:

public static int counting(int[] x) {
    Map<Integer, Long> map = new HashMap<>(); // key is a number, value is how often does it appear in the array 
    for (int number : x) {
        if (map.get(number) != null) {
            map.put(number, map.get(number) + 1);
        } else {
            map.put(number, 1L);
        }
    }
    return Collections.max(map.entrySet(), Map.Entry.comparingByKey()).getKey();
}

Примечание: есть много способов получить ключ от карты, связанной с максимальным значением. Смотрите здесь, чтобы найти наиболее подходящий способ: Найти ключ, связанный с максимальным значением на карте Java

Также if else оператор может быть заменен методом слияния из java8:

map.merge(number, 1L, (a, b) -> a + b);

Взгляните на эти две строки:

 for (int j = i + 1; j < x.length - 1; j++) {

а также

} else if (j == x.length - 1 && counter >= memory)

Вы пока j строго меньше, чем x.length - 1, но твой else if срабатывает только когда j в точности равно x.length - 1, Таким образом, вы никогда не можете нажать на код в вашем else if блок.

Кроме того, ваш счетчик должен действительно начинаться с единицы, так как вы подсчитываете количество записей, которые соответствуют той, на которую вы просматриваете, поэтому вы пропускаете подсчет первой. Но поскольку вы нигде не выводите счетчик, я думаю, он не очень актуален.

Чтобы исправить ваш код, измените внутренний цикл for, чтобы перейти к j <= x.length - 1,

Объявите две переменные для хранения наиболее распространенного числа и его частоты:

int mostCommon =Integer.MIN_VALUE;

int highFreq = 0;

Переберите ваш массив. Для каждого элемента повторите итерацию по вашему массиву и посчитайте его частоту. Если текущий счет больше чем highFreq Обновить mostCommon установив его на текущий элемент и установить highFreq текущий счет. Пример:

public class countingNumbers{

    public static void main(String[] args) {
        int[] res = counting(new int[]{6, 4, 5, 4, 5, 6, 4, 3, 2});
        System.out.println("most common number is: " + res[0] + " with " + res[1] + " counts");
    }

    public static int[] counting(int[] x) {
        int mostCommon = Integer.MIN_VALUE;
        int highFreq = 0;
        for (int i = 0; i < x.length; i++) {
            int currFreq = 0;
            for (int j = 0; j < x.length; j++) {
                if (x[i] == x[j]) {
                    currFreq++;
                }
            }
            if (highFreq < currFreq) {
                highFreq = currFreq;
                mostCommon = x[i];
            }
        }
        return new int[]{mostCommon, highFreq};
    }
}
Другие вопросы по тегам