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

Разбор числа по цифрам

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

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

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

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

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

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

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

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

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

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

теория

Число как запись

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

Задачи звучат так: сумма цифр, наибольшая цифра, палиндром ли число, сколько в нём двоек. Все они об одном — как добраться до цифры.

Инструментов ровно два, и оба вы уже знаете:

действие что даёт пример
n % 10 последнюю цифру 1234 % 10 → 4
n // 10 число без последней цифры 1234 // 10 → 123

Первый достаёт цифру, второй сдвигает число, открывая следующую. Больше ничего не нужно.

Позже вы узнаете, что число можно превратить в строку и пройтись по символам. Это тоже рабочий способ, но он прячет от вас разряды — а на них дальше держатся системы счисления и целый класс олимпиадных задач. Поэтому здесь только арифметика.

теория

Основной цикл разбора

Два действия соединяются в цикл, который надо запомнить наизусть — он встретится в каждой задаче занятия:

n = int(input())
s = 0

while n > 0:
    digit = n % 10      # взяли последнюю цифру
    s += digit          # что-то с ней сделали
    n //= 10            # отбросили её

print(s)

Проследим на 1234, шаг за шагом:

шаг n digit s
1 1234 4 4
2 123 3 7
3 12 2 9
4 1 1 10
0 цикл кончился

Цифры идут справа налево. Это важно: если задача про первую цифру или про порядок цифр, разбор выдаёт их в обратном порядке, и это надо учитывать, а не игнорировать.

И обратите внимание, что число n по ходу разрушается. Если оно понадобится в конце — например, чтобы сравнить с перевёрнутым, — сохраните его копию до цикла.

тест

Проверка: что будет с нулём

Программа считает количество цифр обычным разбором:

count = 0
while n > 0:
    n //= 10
    count += 1

Что она выведет при n = 0?

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

Собрать число обратно

Разобрать — половина дела. Часто нужно построить новое число из цифр: перевернуть запись, выкинуть лишние цифры, оставить только чётные.

Приём зеркальный разбору:

result = result * 10 + digit

Умножение на 10 сдвигает уже собранное на разряд влево, а прибавление ставит новую цифру в освободившееся место. Переворот числа целиком:

n = int(input())
result = 0

while n > 0:
    result = result * 10 + n % 10
    n //= 10

print(result)

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

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

kept = 0
power = 1

while n > 0:
    digit = n % 10
    if digit != 3:
        kept += digit * power
        power *= 10        # разряд растёт только когда цифру оставили
    n //= 10

Последняя строка с power — то место, где ошибаются чаще всего: разряд должен расти только для оставленных цифр.

теория

Разряды и степени десятки

Иногда нужна не «очередная» цифра, а конкретная — третья справа, или всё, что стоит левее неё. Здесь работают степени десятки.

выражение смысл
n % 100 две последние цифры
n // 100 всё, кроме двух последних
n // 10 ** k % 10 цифра на позиции kk справа, нумерация с нуля

Отсюда получается и вычёркивание цифры по позиции — целиком арифметикой, без перебора всех цифр:

left = n // 10 ** (k + 1)     # всё слева от цифры
right = n % 10 ** k           # всё справа от неё
result = left * 10 ** k + right

Такой приём нужен в задачах вида «вычеркните одну цифру, чтобы число стало наибольшим»: позиций всего девятнадцать даже у числа до 101810^{18}, и каждую можно просто перебрать.

расчёт

Проверка: сумма цифр

Чему равна сумма цифр числа 90807? Введите целое число.

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

Три ошибки этого занятия

Ноль. Цикл while n > 0 при n = 0 не выполняется ни разу. Для суммы цифр это случайно верно, для количества цифр — уже нет: ответ должен быть 1. Если ноль допустим по условию, обработайте его отдельной строкой.

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

Разряд, растущий не там. При сборке с пропуском цифр power *= 10 должно стоять внутри условия. Снаружи оно оставит дырки: вычеркнутая цифра превратится в ноль вместо того, чтобы исчезнуть.

Как проверять себя

Три входа, которые ловят почти всё:

  • 0 — выполняется ли то, что должно;
  • однозначное число — не рассчитывает ли программа хотя бы на две цифры;
  • число с нулями внутри и на конце, например 1000 или 50805 — не теряются ли они и не портят ли сборку.
теория

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

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

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

Числа доходят до 101810^{18} — это 19 цифр. Никакой особой обработки для них не нужно: целые в Python неограниченные, а цикл разбора всё равно делает не больше двух десятков шагов.

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

Палиндром, который не работает

Задача: «дано число nn, определите, читается ли оно одинаково в обе стороны».

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

n = int(input())
result = 0

while n > 0:
    result = result * 10 + n % 10
    n //= 10

if result == n:
    print("YES")
else:
    print("NO")

Программа отвечает NO даже для числа 12321. Объясните, что именно происходит, какой ответ она даёт для 0, и как это исправить.

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