← Назад к вопросам
Первый неповторяющийся символ
2.3 Middle🔥 171 комментариев
#Теория тестирования
Условие
Напишите функцию, которая находит первый неповторяющийся символ в строке.
Пример
Вход: leetcode Выход: l
Вход: loveleetcode Выход: v
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Решение: Первый неповторяющийся символ
Эта задача требует поиска первого символа, который встречается только один раз в строке. Решается за два прохода по строке: первый для подсчёта частоты символов, второй для поиска первого неповторяющегося.
Алгоритм решения
- Создаём словарь/хеш-таблицу для подсчёта частоты каждого символа
- Первый проход: Проходим по строке и считаем, сколько раз встречается каждый символ
- Второй проход: Проходим по строке заново и возвращаем первый символ с частотой 1
- Если таких нет: Возвращаем -1 или None (в зависимости от требований)
Реализация решения
def firstUniqChar(s: str) -> int:
"""
Находит индекс первого неповторяющегося символа.
Args:
s: Входная строка
Returns:
Индекс первого неповторяющегося символа или -1 если такого нет
"""
# Подсчитываем частоту каждого символа
char_count = {}
for char in s:
char_count[char] = char_count.get(char, 0) + 1
# Ищем первый символ с частотой 1
for i, char in enumerate(s):
if char_count[char] == 1:
return i
# Если неповторяющегося символа нет
return -1
# Альтернативный вариант, возвращающий сам символ
def firstUniqCharSymbol(s: str) -> str:
"""
Находит первый неповторяющийся символ в строке.
Returns:
Первый неповторяющийся символ или пустая строка
"""
char_count = {}
for char in s:
char_count[char] = char_count.get(char, 0) + 1
for char in s:
if char_count[char] == 1:
return char
return ""
Пошаговый разбор примеров
Пример 1: "leetcode"
Первый проход (подсчёт частоты):
char_count = {
l: 1,
e: 3,
t: 1,
c: 1,
o: 1,
d: 1
}
Второй проход (поиск первого неповторяющегося):
- Индекс 0: l, char_count[l] = 1 → Возвращаем 0 (или символ l)
Выход: 0 (или l) ✓
Пример 2: "loveleetcode"
Первый проход (подсчёт частоты):
char_count = {
l: 2,
o: 2,
v: 1,
e: 4,
t: 1,
c: 1,
d: 1
}
Второй проход (поиск первого неповторяющегося):
- Индекс 0: l, char_count[l] = 2 → пропускаем
- Индекс 1: o, char_count[o] = 2 → пропускаем
- Индекс 2: v, char_count[v] = 1 → Возвращаем 2 (или символ v)
Выход: 2 (или v) ✓
Реализация с использованием Counter
from collections import Counter
def firstUniqChar_with_counter(s: str) -> int:
"""
Использует Counter из модуля collections для упрощения кода
"""
char_count = Counter(s)
for i, char in enumerate(s):
if char_count[char] == 1:
return i
return -1
Реализация с сохранением порядка вставки (OrderedDict)
from collections import OrderedDict
def firstUniqChar_ordered(s: str) -> int:
"""
Использует OrderedDict для явного сохранения порядка
(хотя с Python 3.7+ обычный dict тоже сохраняет порядок)
"""
char_count = OrderedDict()
for char in s:
char_count[char] = char_count.get(char, 0) + 1
for i, char in enumerate(s):
if char_count[char] == 1:
return i
return -1
Тестовые случаи
# Основные примеры
print(firstUniqChar("leetcode")) # 0
print(firstUniqCharSymbol("leetcode")) # "l"
print(firstUniqChar("loveleetcode")) # 2
print(firstUniqCharSymbol("loveleetcode")) # "v"
# Граничные случаи
print(firstUniqChar("")) # -1
print(firstUniqChar("a")) # 0
print(firstUniqChar("aa")) # -1
print(firstUniqChar("aabbcc")) # -1
print(firstUniqChar("abcdefg")) # 0
print(firstUniqChar("aabccd")) # 3
# Специальные случаи
print(firstUniqChar(" a b ")) # 2 (пробелы тоже символы)
print(firstUniqChar(".,.,.,a")) # 6
Сложность
- Временная сложность: O(n), два линейных прохода по строке
- Пространственная сложность: O(1), в худшем случае O(k), где k — размер алфавита (максимум 26 для букв, 128-256 для ASCII, 1114112 для Unicode, но практически ограничено входными данными)
Оптимизация для больших строк
def firstUniqChar_optimized(s: str) -> int:
"""
Если строка содержит много одинаковых символов,
можем выйти рано из второго прохода
"""
if not s:
return -1
char_count = {}
for char in s:
char_count[char] = char_count.get(char, 0) + 1
# Второй проход с ранним выходом
for i in range(len(s)):
if char_count[s[i]] == 1:
return i
return -1
Важные детали
- Регистр символов имеет значение (A ≠ a)
- Пробелы и специальные символы считаются обычными символами
- Пустая строка возвращает -1
- Строка из одного символа всегда возвращает индекс 0
Решение оптимально, имеет линейную сложность и подходит для production-кода.