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