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};
}
}