Получение индекса элемента массива, который встречается чаще всего
Мне нужно вывести индекс второго с конца элемента, который встречается в массиве чаще всего.
Например, есть массив [100 76 84 66 66 122 76 443 9 12 66 12]. Здесь чаще всего встречается число 66. У него индексы 3, 4 и 10. Нужно, чтобы программа вывела 4(второй индекс с конца). Если несколько значений встречаются в массиве одинаковое количество раз, то нужно выбрать наибольшее по модулю значение, а потом просто наибольшее значение.
У меня есть код, но он работает не совсем правильно, вернее совсем не работает:
public static int absMaxFrequentNumber(int[] array) {
int maxCount = 0;
int index = 0;
int maxNumber = array[0];
for (int i = 0; i < array.length; i++) {
int count = 0;
for (int j = 0; j < array.length; j++) {
if (array[i] == array[j] && Math.abs(array[i]) >= maxNumber) {
count++;
}
if (count >= maxCount) {
maxCount = count;
index = i;
}
}
}
if (maxCount == 1){
return -1;
}else {
return index;
}
}
public static int maxFrequentNumber(int[] array) {
int maxCount = 0;
int index = 0;
int maxNumber = array[0];
for (int i = 0; i < array.length; i++) {
int count = 0;
for (int j = 0; j < array.length; j++) {
if (array[i] == array[j]) {
count++;
}
if (count >= maxCount && array[i] >= maxNumber) {
maxCount = count;
index = i;
}
}
}
if (maxCount == 1){
return -1;
}else {
return index;
}
}
Подскажите, пожалуйста, что нужно сделать, я новичок в java
Также, при попытке вызвать функции, пишет ошибку:
Result of 'Main.absMaxFrequentNumber()' is ignored
Result of 'Main.maxFrequentNumber()' is ignored
Ответы (3 шт):
Мы можем создать объект типа
Map, который будет хранить элемент и список индексов этого элемента.При просмотре массива мы добавляем в map пару число - список с его индексом, если такого числа не было в map ранее, а если присутствовал, то получаем список для данного числа, и помещаем туда еще один индекс.
После ищем максимальный по размеру список среди всех в данном map и сохраняем его индекс.
Если таких списков несколько, то выбираем наибольшее по модулю значение.
Выводим на экран size() - 2 элемент, так как это предпоследний с конца элемент.
int[] array = {100, 76, 84, 66, 66, 122, 76,443, 9, 12, 66, 12}; Map<Integer, List<Integer>> map = new HashMap<>(); for(int i = 0; i < array.length; i++) { if(!map.containsKey(array[i])) { List<Integer> list = new ArrayList<>(); list.add(i); map.put(array[i], list); } else { List<Integer> list = map.get(array[i]); list.add(i); map.put(array[i], list); } } int maxSize = 0; int maxInt = 0; for(Integer i : map.keySet()) { if(map.get(i).size() > maxSize) { maxSize = map.get(i).size(); maxInt = i; } else if(map.get(i).size() == maxSize) { if(Math.abs(i) > Math.abs(maxInt)) { maxInt = i; } } } List<Integer> list = map.get(maxInt); System.out.println(list.get(list.size() - 2));
Суть задач на нахождение повторений - использование колекций Map и Set.
Все хорошо, но слишком много кода, читаемость нулевая и в этом основная проблема. Я бы смотрел в сторону функционалки, сделал примерно так, а потом уже рефакторил (это за вами):
import java.util.Arrays;
import java.util.Comparator;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Test {
public static void main(String[] args) {
Integer [] arr = {100, 76, 84, 66, 66, 122, 76, 443, 9, 12, 66, 12};
Integer number = Arrays.stream(arr)
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet().stream().max(Comparator.comparingLong(Entry::getValue)).get().getKey();
int[] result = IntStream.range(0, arr.length)
.filter(i->number.equals(arr[i]))
.toArray();
System.out.println(Arrays.toString(result));
}
}
Функциональное решение с использованием Stream API и компараторов, в случае ненахождения нужного элемента возвращается -1
- поток индексов группируется по значениям в массиве в карту
Map<Integer, List<Integer>> - поток элементов карты фильтруется, чтобы исключить элементы, встречающиеся менее 2 раз
- находится требуемый элемент карты при помощи компаратора как
Optional<Map.Entry> - используем
Optional::map+Optional::orElseчтобы вернуть нужный результат
public static int secondIndexOfMostFrequent(int ... arr) {
System.out.print(Arrays.toString(arr) + " -> ");
return IntStream
.range(0, arr.length)
.boxed() // Stream<Integer> индексы в массиве
.collect(Collectors.groupingBy(i -> arr[i])) // Map<Integer, List<Integer>>
.entrySet()
.stream() // Stream<Map.Entry<Integer, List<Integer>>> значение=список индексов
.filter(e -> e.getValue().size() > 1) //
.max(Map.Entry.<Integer, List<Integer>>comparingByValue(
Comparator.comparingInt(List::size))
.thenComparingInt(e -> Math.abs(e.getKey()))
.thenComparingInt(Map.Entry::getKey)
) // Optional<Map.Entry>
.map(Map.Entry::getValue) // Optional<List<Integer>>
.map(indexes -> indexes.get(indexes.size() - 2)) // Optional<Integer> 2nd index
.orElse(-1);
}
Тесты:
int[][] tests = {
{},
{1},
{2, 2},
{100, -76, 84, 66, 66, 122, -76, 443, 9, 12, 66, 12, -76},
{100, -76, 84, 76, 76, 122, -76, 443, 9, 12, 76, 12, -76},
{100, 76, 84, 65, 63, 122, 75, 443, 9, 12, 66, 1}
};
for (int[] arr : tests) {
int secondIndex = secondIndexOfMostFrequent(arr);
System.out.println("arr[" + secondIndex + "] = " + (secondIndex > -1 ? "" + arr[secondIndex] : "NULL"));
}
Результаты:
[] -> arr[-1] = NULL
[1] -> arr[-1] = NULL
[2, 2] -> arr[0] = 2
[100, -76, 84, 66, 66, 122, -76, 443, 9, 12, 66, 12, -76] -> arr[6] = -76
[100, -76, 84, 76, 76, 122, -76, 443, 9, 12, 76, 12, -76] -> arr[4] = 76
[100, 76, 84, 65, 63, 122, 75, 443, 9, 12, 66, 1] -> arr[-1] = NULL
Аналогичное решение без применения Stream API:
static int nonStreamAPI(int ... array) {
Map<Integer, List<Integer>> map = new HashMap<>();
int ix = 0;
for (int x : array) {
map.computeIfAbsent(x, (k) -> new ArrayList<>()).add(ix++);
}
Map.Entry<Integer, List<Integer>> max = null;
for (Map.Entry<Integer, List<Integer>> e : map.entrySet()) {
if (e.getValue().size() > 1) {
if (null == max
|| max.getValue().size() < e.getValue().size()
|| Math.abs(max.getKey()) < Math.abs(e.getKey())
|| Math.abs(max.getKey()) == Math.abs(e.getKey())
&& max.getKey() < e.getKey()
) {
max = e;
}
}
}
return null == max ? -1 : max.getValue().get(max.getValue().size() - 2);
}