Редакция для Разбор лога


Remember to use this editorial only when stuck, and not to copy-paste code from it. Please be respectful to the problem author and editorialist.
Submitting an official solution before solving the problem yourself is a bannable offence.

1. Идея

Нужно разбить строку по одному символу-разделителю и вывести все получившиеся части по одной в строке.

Главная тонкость: если два разделителя идут подряд, между ними находится пустое поле. Его тоже надо вывести. То же самое относится к разделителю в начале или в конце строки: там тоже появляются пустые поля.

Самый простой способ — пройти по строке слева направо, накапливать текущий фрагмент, а когда встречается разделитель, сразу выводить накопленное поле и начинать собирать следующее.


2. Наблюдения

  1. Разделитель состоит ровно из одного символа, поэтому не нужно искать длинные подстроки.

  2. Если текущий символ не равен разделителю, он относится к текущему полю.

  3. Если текущий символ равен разделителю:

    • текущее поле заканчивается;
    • его нужно вывести;
    • новое поле начинается сразу после разделителя.
  4. После окончания прохода по строке нужно вывести последнее поле. Это важно, потому что строка может не заканчиваться разделителем.

  5. Пустые поля обрабатываются автоматически:

    • если current пуст, а встретился разделитель, мы просто выводим пустую строку;
    • если в конце строки стоит разделитель, после него остаётся пустое последнее поле, и оно будет выведено финальным print или cout.

3. Алгоритм

  1. Считать первую строку и взять её первый символ как разделитель.
  2. Считать строку лога.
  3. Завести переменную current для текущего поля.
  4. Для каждого символа строки:
    • если это разделитель:
      • вывести current;
      • очистить current;
    • иначе добавить символ в current.
  5. После цикла вывести 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))

Комментарии

Еще нет ни одного комментария.