Редакция для Первый неповторяющийся символ
Submitting an official solution before solving the problem yourself is a bannable offence.
Разбор задачи «Первый неповторяющийся символ»
1. Идея
Нужно найти первый символ строки, который встречается ровно один раз во всей строке, и вывести его позицию с нумерацией с 1.
Самая удобная идея — сделать это в два прохода:
- Сначала посчитать, сколько раз встречается каждая буква.
- Затем пройти по строке слева направо и найти первый символ, у которого частота равна 1.
Так как строка состоит только из строчных латинских букв, достаточно хранить частоты в массиве размера 26.
2. Наблюдения
- Нас интересуют только буквы
'a'...'z', значит можно использовать массивcntдлины 26. - Для буквы
cиндекс в массиве можно получить какc - 'a'в C++ илиord(c) - ord('a')в Python. - Если во втором проходе встретился символ с частотой 1, это и есть ответ, потому что мы идём слева направо.
- Если после полного прохода такой символ не найден, нужно вывести
-1.
Пример: строка abac
- частоты:
a— 2b— 1c— 1
- идём по строке:
a— не подходитb— подходит, значит ответ2
3. Алгоритм
- Считать строку
s. - Создать массив
cntиз 26 нулей. - Для каждого символа строки увеличить соответствующий счётчик.
- Ещё раз пройти по строке по индексам:
- если частота текущего символа равна 1, вывести
i + 1и завершить программу.
- если частота текущего символа равна 1, вывести
- Если подходящий символ не найден, вывести
-1.
4. Почему это работает
После первого прохода в массиве cnt для каждой буквы хранится точное количество её вхождений в строку.
Во втором проходе мы рассматриваем символы в том же порядке, в котором они стоят в строке. Как только встречаем символ с частотой 1, это означает:
- он встречается ровно один раз во всей строке;
- среди всех таких символов он расположен левее остальных, потому что мы идём слева направо.
Значит, первый найденный во втором проходе символ и есть первый неповторяющийся символ строки.
Если ни один символ не имеет частоту 1, ответа не существует, поэтому правильно вывести -1.
5. Сложность
- Первый проход по строке:
O(n) - Второй проход по строке:
O(n) - Итого:
O(n)
Дополнительная память:
- массив из 26 чисел, то есть
O(1)
6. Код на C++17
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
string s;
cin >> s;
vector<int> cnt(26, 0);
for (char c : s) {
cnt[c - 'a']++;
}
for (int i = 0; i < (int)s.size(); i++) {
if (cnt[s[i] - 'a'] == 1) {
cout << i + 1 << '\n';
return 0;
}
}
cout << -1 << '\n';
return 0;
}
7. Код на Python 3
s = input()
cnt = [0] * 26
for c in s:
cnt[ord(c) - ord('a')] += 1
for i in range(len(s)):
if cnt[ord(s[i]) - ord('a')] == 1:
print(i + 1)
break
else:
print(-1)
Комментарии