Как найти наиболее часто встречающийся символ в строке

Строки — важная тема на собеседованиях. Практика задач по строкам помогает быстрее решать такие задачи. В этой статье вы узнаете, как найти символ, который встречается в строке чаще других.
Примеры для понимания задачи
Пример 1: Пусть задана строка «Makeuseof». Символ «e» встречается 2 раза, все остальные — по одному. Значит, «e» — наиболее частый.
Пример 2: Пусть задана строка «She sees cheese». Символ «e» встречается 6 раз, все остальные — реже. Значит, «e» — наиболее частый.
Подход для поиска наиболее частого символа в строке
Самый эффективный и распространённый способ — использовать хэширование: пройти строку и подсчитать частоту каждого символа в фиксированном массиве (например, по кодам ASCII) или в словаре/хэше. После этого найти индекс (символ) с максимальной частотой.
Идея для строки “Makeuseof”:
frequency[‘M’] = 1
frequency[‘a’] = 1
frequency[‘k’] = 1
frequency[‘e’] = 2
frequency[‘u’] = 1
frequency[‘s’] = 1
frequency[‘o’] = 1
frequency[‘f’] = 1
Максимальное значение — 2, индекс соответствует символу ‘e’.
C++ программа для поиска символа с наибольшей частотой
Ниже — исходный код на C++, реализующий описанный метод.
// C++ program to find the character
// having the highest frequency in a string
#include
#include
#define ASCII_SIZE 256
using namespace std;
char maxFrequencyChar(string str)
{
// Array to store frequency of each characters
// Initialized the frequency of each character as 0
int frequency[ASCII_SIZE] = {0};
// Finding length of the input string
int lenOfStr = str.length();
// Initialize maxFrequency variable
int maxFrequency = -1;
// Initialize maxFrequencyChar variable
char maxFrequencyChar;
// Traversing and maintaining the
// frequency of each characters
for (int i = 0; i < lenOfStr; i++)
{
frequency[str[i]]++;
if (maxFrequency < frequency[str[i]])
{
maxFrequency = frequency[str[i]];
maxFrequencyChar = str[i];
}
}
return maxFrequencyChar;
}
// Driver Code
int main()
{
string str1 = "Which witch is which?";
cout << "str1: " << str1 << endl;
cout << "The highest frequency character is: " << maxFrequencyChar(str1) << endl;
string str2 = "He threw three free throws";
cout << "str2: " << str2 << endl;
cout << "The highest frequency character is: " << maxFrequencyChar(str2) << endl;
string str3 = "Eddie edited it";
cout << "str3: " << str3 << endl;
cout << "The highest frequency character is: " << maxFrequencyChar(str3) << endl;
string str4 = "Makeuseof";
cout << "str4: " << str4 << endl;
cout << "The highest frequency character is: " << maxFrequencyChar(str4) << endl;
string str5 = "She sees cheese";
cout << "str5: " << str5 << endl;
cout << "The highest frequency character is: " << maxFrequencyChar(str5) << endl;
}
Вывод программы (пример):
str1: Which witch is which?
The highest frequency character is: h
str2: He threw three free throws
The highest frequency character is: e
str3: Eddie edited it
The highest frequency character is: d
str4: Makeuseof
The highest frequency character is: e
str5: She sees cheese
The highest frequency character is: ePython программа для поиска символа с наибольшей частотой
Ниже — реализация на Python. В исходном примере используется массив размера 256 для ASCII.
# Python program to find the character
# having the highest frequency in a string
ASCII_SIZE = 256
def maxFrequencyChar(str):
# Array to store frequency of each characters
# Initialized the frequency of each character as 0
frequency = [0] * ASCII_SIZE
# Initialize maxFrequency variable
maxFrequency = -1
# Initialize maxFrequencyChar variable
maxFrequencyChar = ''
# Traversing and maintaining the
# frequency of each characters
for i in str:
frequency[ord(i)] += 1
for i in str:
if maxFrequency < frequency[ord(i)]:
maxFrequency = frequency[ord(i)]
maxFrequencyChar = i
return maxFrequencyChar
# Driver Code
str1 = "Which witch is which?"
print("str1:", str1)
print("The highest frequency character is:", maxFrequencyChar(str1))
str2 = "He threw three free throws"
print("str2:", str2)
print("The highest frequency character is:", maxFrequencyChar(str2))
str3 = "Eddie edited it"
print("str3:", str3)
print("The highest frequency character is:", maxFrequencyChar(str3))
str4 = "Makeuseof"
print("str4:", str4)
print("The highest frequency character is:", maxFrequencyChar(str4))
str5 = "She sees cheese"
print("str5:", str5)
print("The highest frequency character is:", maxFrequencyChar(str5))
Вывод (пример):
str1: Which witch is which?
The highest frequency character is: h
str2: He threw three free throws
The highest frequency character is: e
str3: Eddie edited it
The highest frequency character is: d
str4: Makeuseof
The highest frequency character is: e
str5: She sees cheese
The highest frequency character is: eC программа для поиска символа с наибольшей частотой
Пример на C из исходного материала (обратите внимание: в исходнике используются заголовки и стиль, приближённые к C++). Код сохранён для демонстрации подхода в языке C-подобном формате.
// C program to find the character
// having the highest frequency in a string
#include
#include
#define ASCII_SIZE 256
using namespace std;
char maxFrequencyChar(char *str)
{
// Array to store frequency of each characters
// Initialized the frequency of each character as 0
int frequency[ASCII_SIZE] = {0};
// Finding length of the input string
int lenOfStr = strlen(str);
// Initialize maxFrequency variable
int maxFrequency = 0;
// Initialize maxFrequencyChar variable
char maxFrequencyChar;
// Traversing and maintaining the
// frequency of each characters
for (int i = 0; i < lenOfStr; i++)
{
frequency[str[i]]++;
if (maxFrequency < frequency[str[i]])
{
maxFrequency = frequency[str[i]];
maxFrequencyChar = str[i];
}
}
return maxFrequencyChar;
}
// Driver Code
int main()
{
char str1[] = "Which witch is which?";
printf("str1: %s", str1);
printf("The highest frequency character is: %c \n", maxFrequencyChar(str1));
char str2[] = "He threw three free throws";
printf("str2: %s", str2);
printf("The highest frequency character is: %c \n", maxFrequencyChar(str2));
char str3[] = "Eddie edited it";
printf("str3: %s", str3);
printf("The highest frequency character is: %c \n", maxFrequencyChar(str3));
char str4[] = "Makeuseof";
printf("str4: %s", str4);
printf("The highest frequency character is: %c \n", maxFrequencyChar(str4));
char str5[] = "She sees cheese";
printf("str1: %s", str5);
printf("The highest frequency character is: %c \n", maxFrequencyChar(str5));
} Вывод (пример):
str1: Which witch is which?
The highest frequency character is: h
str2: He threw three free throws
The highest frequency character is: e
str3: Eddie edited it
The highest frequency character is: d
str4: Makeuseof
The highest frequency character is: e
str5: She sees cheese
The highest frequency character is: eJavaScript программа для поиска символа с наибольшей частотой
Реализация на JavaScript сохраняет ту же идею — массив фиксированного размера для кодов символов.
// JavaScript program to find the character
// having the highest frequency in a string
let ASCII_SIZE = 256;
function maxFrequencyChar(str)
{
// Array to store frequency of each characters
// Initialized the frequency of each character as 0
let frequency = new Array(ASCII_SIZE);
for (let i = 0; i < ASCII_SIZE; i++)
{
frequency[i] = 0;
}
// Finding length of the input string
let lenOfStr = str.length;
for (let i = 0; i < lenOfStr; i++)
{
frequency[str[i].charCodeAt(0)] += 1;
}
// Initialize maxFrequency variable
let maxFrequency = -1;
// Initialize maxFrequencyChar variable
let maxFrequencyChar = '';
// Traversing and maintaining the
// frequency of each characters
for (let i = 0; i < lenOfStr; i++)
{
if (maxFrequency < frequency[str[i].charCodeAt(0)])
{
maxFrequency = frequency[str[i].charCodeAt(0)];
maxFrequencyChar = str[i];
}
}
return maxFrequencyChar;
}
// Driver Code
let str1 = "Which witch is which?";
document.write("str1: " + str1 + "\n");
document.write("The highest frequency character is: " + maxFrequencyChar(str1) + "\n")
let str2 = "He threw three free throws";
document.write("str2: " + str2 + "\n");
document.write("The highest frequency character is: " + maxFrequencyChar(str2) + "\n")
let str3 = "Eddie edited it";
document.write("str3: " + str3 + "\n");
document.write("The highest frequency character is: " + maxFrequencyChar(str3) + "\n")
let str4 = "Makeuseof";
document.write("str4: " + str4 + "\n");
document.write("The highest frequency character is: " + maxFrequencyChar(str4) + "\n")
let str5 = "She sees cheese";
document.write("str5: " + str5 + "\n");
document.write("The highest frequency character is: " + maxFrequencyChar(str5) + "\n")Вывод (пример):
str1: Which witch is which?
The highest frequency character is: h
str2: He threw three free throws
The highest frequency character is: e
str3: Eddie edited it
The highest frequency character is: d
str4: Makeuseof
The highest frequency character is: e
str5: She sees cheese
The highest frequency character is: eАнализ временной и пространственной сложности
Для функции maxFrequencyChar() время работы — O(n), где n — длина строки: один проход для подсчёта частот и (в худшем случае) дополнительный проход для поиска максимума, но можно сделать всё в одном проходе. Пространственная сложность — O(1), если используется фиксированный массив (например, размер 256 для ASCII). Если использовать динамический словарь для произвольных символов Unicode, то сложность памяти — O(k), где k — число уникальных символов в строке.
Важно помнить, что «фиксированный массив 256» применим только когда вход ограничен ASCII. Для Unicode (UTF-8/UTF-16) нужен другой подход — словарь/Map или предварительная нормализация.
Когда подход с фиксированным массивом не сработает
- В строках с Unicode-символами (эмодзи, многобайтовые символы) индексация по байту даст неверный результат. Используйте словарь/Map и работайте с кодовыми точками.
- Если нужно игнорировать регистр, предварительно приведите строку к одному регистру.
- Если нужно игнорировать пробелы или знаки пунктуации — отфильтруйте их заранее.
- В случае равной максимальной частоты (ничья) алгоритм выше возвращает первый встретившийся максимальный символ. Если нужна другая политика (например, минимальный/лексикографический), требуется дополнительная логика.
Альтернативные подходы
- Сортировка символов и проход по отсортированной строке: O(n log n) по времени, O(1) или O(n) по памяти в зависимости от реализации.
- Использовать структуру данных Counter (collections.Counter в Python) или HashMap/unordered_map в C++ для гибкой работы с Unicode.
- Для потоковых входных данных (stream) можно поддерживать счётчики и периодически сохранять топ-k.
Хитрости и эвристики
- Для ASCII используйте фиксированный массив размера 256 — быстрее и экономнее по памяти.
- Для текста на естественных языках чаще всего полезно нормализовать строку (Unicode NFC/NFD), убрать диакритические знаки, привести к единому регистру.
- Если важна скорость и вход очень большой, оцените локальность данных и кэширование: массив по индексам символов работает лучше, чем HashMap.
Небольшая таблица с важными числами
- Время: O(n)
- Память: O(1) для фиксированного массива, O(k) для словаря (k — число уникальных символов)
- Размер массива для ASCII: 256
Проверочные случаи и критерии приёмки
- Пустая строка -> поведение: можно возвращать пустой символ или бросать исключение.
- Строка с одним символом -> возвращается этот символ.
- Строки с Unicode-символами -> результат корректен при использовании Map/словаря.
- Равная частота -> документировать политику выбора (первый/последний/лексикографический).
Примеры тестов (вход -> ожидаемый символ):
- “” -> (ошибка или пусто)
- “aaaa” -> ‘a’
- “ababa” -> ‘a’ (если выбираем первый встреченный)
- “A a a” -> зависит от фильтрации/регистра
Decision flowchart
flowchart TD
A[Есть требование к Unicode?] -->|Да| B{Использовать Map}
A -->|Нет| C{Вход ограничен ASCII?}
C -->|Да| D[Использовать массив size=256]
C -->|Нет| B
B --> E[Нормализация строки + Map подсчёт]
D --> E
E --> F[Найти максимум и применить политику ничьей]Короткий глоссарий
- Хэш/словарь: структура, где ключ — символ, значение — счётчик.
- Кодовая точка: уникальный числовой код символа в Unicode.
- Нормализация: приведение Unicode-строки к единому представлению.
Заключение
Метод подсчёта частот символов — простой, эффективный и широко применимый. Для ASCII достаточно фиксированного массива размера 256 и линейного времени. Для Unicode и особых требований (регистрозависимость, игнорирование пробелов, политика при ничьей) используйте словари/Map и заранее нормализуйте строку.
Важно: определите требования к входу и правила обработки (регистр, пробелы, пунктуация, Unicode) перед выбором реализации.
Список ключевых выводов:
- Простое решение: подсчитать частоты и найти максимум — O(n).
- Для ASCII можно использовать массив размера 256 — O(1) памяти.
- Для Unicode используйте Map/словарь и нормализацию.
- Документируйте поведение при ничьей и при пустой строке.
Похожие материалы
CSS font-family: как менять шрифты на сайте
График амортизации кредита в Excel — пошагово
Разгон Raspberry Pi 4 — безопасный пошаговый гид
Как запустить Windows 11 на Mac — варианты и советы
Мошенничество с возвратом средств через техподдержку