EduBrick
классная работа

Практикум по строкам

Программирование на Python: от нуля до олимпиад

0/19решено 0 из 19до зачёта осталось 10

Чему научитесь

  • Выбирать между перебором, методом, срезом и кодами по условию задачи
  • Соединять приёмы модуля в одном решении
  • Находить чужие ошибки и отличать их по симптому
  • Замечать, когда верное решение не пройдёт по времени

Как устроено занятие

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

Дальше 15 задач лестницей: разминка, основа, со звёздочкой. Занятие засчитывается, когда решено 10 — остальные не пропадают и учитываются отдельно.

После занятия — вторая часть, ещё 15 задач на те же приёмы в новых сюжетах.

Сколько это займёт

Примерно час-полтора вместе с задачами. Сроков нет: можно закрыть вкладку и вернуться когда удобно — прогресс сохранится.

теория

Четыре способа сделать одно и то же

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

инструмент занятие когда он лучший
перебор символов 13 условие сложнее равенства: соседи, позиции, накопление
методы 14 готовая операция: посчитать, найти, заменить, разбить
срезы 15 нужен кусок: край, середина, разворот, сдвиг
коды ord и chr 16 буква участвует в арифметике: сдвиги, номера, регистр

Задача «сколько раз встречается буква» решается методом count — и это правильный ответ. Задача «сколько раз буква стоит рядом с такой же» методом не решается вовсе: там нужен перебор с номерами.

Практическое правило: сначала посмотрите, нет ли готового метода. Если есть — берите. Если условие требует чего-то, чего в списке методов нет, — возвращайтесь к циклу.

Сегодня темы не подписаны, и рядом стоящие задачи почти никогда не про одно и то же.

тест

Проверка: чем решать

Условие: «дана строка; выведите её без символов, которые совпадают с предыдущим».

Каким средством это делается?

Войдите, чтобы ответить.
теория

Что ломается в задачах на строки

Ошибки модуля собраны вместе — с признаком, по которому каждая узнаётся.

Границы

  1. s[i + 1] на последнем шаге цикла. Признак: string index out of range.
  2. Срез на единицу короче или длиннее. Признак: ответ похож на правильный, но не тот. Сообщения нет — срез не падает.
  3. s[-k:] при k = 0 даёт всю строку, а не пустую.

Неизменяемость

  1. s.replace(...) без присваивания. Признак: программа выводит то, что ввели.
  2. s[0] = "x" — так нельзя, строка собирается заново.

Пустое и вырожденное

  1. Строка из одного символа: нет соседей, первый и последний совпадают.
  2. split() на строке из пробелов даёт пустой список — цикл не выполнится ни разу.
  3. Искомого нет: find вернёт −1, и это не позиция.

Коды

  1. Забытый % 26 — сдвиг уезжает за z в посторонние знаки.
  2. Перепутанные ord("a") и ord("A") для разных регистров.
теория

И ещё про скорость

В задачах на строки есть отдельная ловушка: решение верное, а времени не хватает.

Чаще всего виноват поиск внутри перебора. Например, «сколько различных символов в строке» через проверку каждого символа против всех предыдущих — это n2n^2 действий. На строке в сто тысяч символов получается десять миллиардов — не пройдёт.

Что делать, зависит от задачи, но два приёма закрывают почти всё:

  • перебирать алфавит, а не строку. Букв всего двадцать шесть. Вместо «для каждого символа проверить остальные» — «для каждой из 26 букв посчитать, сколько раз она встречается». Это 26n26n вместо n2n^2;
  • помнить предыдущее. Задачи про соседей, цепочки и повторы решаются одним проходом, если хранить один символ назад.

Прикидка та же, что в занятии 11: перемножьте длину строки на количество проходов по ней и сравните с десятью миллионами.

теория

Практикум: пятнадцать задач

Лестница прежняя: пять разминочных, семь основных, три со звёздочкой. Зачёт при десяти решённых.

Подсказки в условиях остались, но они про выбор инструмента, а не про решение.

После задач — три разбора чужого кода. Все три программы выглядят правдоподобно, и все три неверны по-разному: одна ошибается на границе, вторая работает верно, но слишком долго, третья ломается на вырожденном вводе. Различать эти три случая по симптому — навык не менее полезный, чем умение писать самому.

лестница задач
развёрнутый ответ

Разбор первый: ошибка на границе

Задача: «дана строка; выведите её последние три символа. Если символов меньше трёх, выведите всю строку».

Ученик написал:

s = input()
print(s[len(s) - 3:])

На строке abcdef программа отвечает верно — def. На строке ab она выводит ab, и это тоже верно. А на строке a выводит a — снова верно.

Ученик считает, что решение правильное. Проверьте это рассуждение: найдите вход, на котором программа ошибается, объясните причину и предложите исправление.

Войдите, чтобы ответить.
развёрнутый ответ

Разбор второй: верно, но долго

Задача: «дана строка из строчных латинских букв длиной до 10510^5; выведите, сколько в ней различных символов».

Ученик написал:

s = input()
count = 0

for i in range(len(s)):
    seen = False
    for j in range(i):
        if s[j] == s[i]:
            seen = True
    if not seen:
        count += 1

print(count)

На коротких примерах программа отвечает правильно, но на больших тестах получает превышение времени. Объясните, сколько примерно действий она делает, почему это не проходит, и предложите решение, которое пройдёт.

Войдите, чтобы ответить.
развёрнутый ответ

Разбор третий: вырожденный вход

Задача: «дана строка, состоящая из слов и пробелов; выведите первое слово. Если слов нет, выведите NONE».

Ученик написал:

s = input()
parts = s.split()

if parts[0] == "":
    print("NONE")
else:
    print(parts[0])

На обычных строках программа работает. На строке из одних пробелов она завершается с ошибкой IndexError: list index out of range. Объясните, что произошло, и как проверить отсутствие слов правильно.

Войдите, чтобы ответить.