Найти самый повторяющуюся букву в строке

Я написал функцию, которая должна шифровать/дешифровать текст, который будет введет в консоли(шифр ROT). Возник вопрос по поводу дешифратора, а конкретнее, как мне определять, какой вариант шифра ROT передо мной(ROT1-25). Я решил использовать следующие аксиомы(шифратор для немецкого языка, так что все аксиомы относятся к данному языку): самая встречающаяся буква в тексте - это буква "е" (по статистике 1 к 5). Теперь предположим, что самая часто встречающаяся буква в шифре, это буква е. Теперь остается лишь определить расстояние между позицией буквы "е" с позицией буквы в шифре, которая её заменяет и можно определить какой вариант шифра ROT был использован. Вопрос возник с тем, как определить самую частую букву в зашифрованном тексте, так как я не понимаю какой тип аргумента консоль передаёт апликации(String?) и если все же String, то как найти в нем самую часту букву(именно букву, а не слово).
Ввод в консоли выглядит вот так: java Encryption decrypt "текст, который нужно обработать".


Ответы (1 шт):

Автор решения: Nowhere Man
  • Отфильтровать буквы во входной строке, например, при помощи String::replaceAll и используя регулярное выражение вида \P{L}, обозначающее не-буквенные символы
  • построить посимвольную карту частот в виде Map<Character, Integer>
  • найти Map.Entry с максимальной частотой и вернуть символ

Решение с использованием Stream API:

public static char mostFrequent(String str) {
    return str.toLowerCase().replaceAll("\\P{L}+", "")
        .chars()
        .mapToObj(c -> (char) c)
        .collect(Collectors.groupingBy(
            c -> c, LinkedHashMap::new, Collectors.summingInt(c -> 1)
        ))
        .entrySet()
        .stream()
        .collect(Collectors.maxBy(Map.Entry.comparingByValue()))
        .map(Map.Entry::getKey)
        .get();
}

Аналогичная реализация с использованием цикла и Map::merge:

public static char mostFrequent(String str) {
    int max = -1;
    char most = '\0';
    Map<Character, Integer> map = new HashMap<>();
    for (char c : str.toLowerCase().replaceAll("\\P{L}+", "").toCharArray()) {
        int freq = map.merge(c, 1, Integer::sum);
        if (freq > max) {
            max = freq;
            most = c;
        }
    }
    return most;
}
→ Ссылка