Обработка целых чисел

Как проверять цифры и делители числа, перебирать пары и находить подходящие значения в заданном диапазоне.

Задание 25

Теория

Границы перебора

Начнём с целых чисел: это числа без дробной части, например −3, 0, 4 и 125. В задании обычно дан отрезок таких чисел, который нужно проверить по очереди.

В условии могут попросить проверить все целые числа от одного значения до другого. Например, на отрезке от 4 до 8 есть пять чисел: 4, 5, 6, 7 и 8. Слова «от ... до ... включительно» означают, что проверяются обе границы.

В Python для такого повтора используют range. Его правая граница не входит в перебор: запись range(4, 8) даёт 4, 5, 6 и 7. Поэтому, если нужно включить число 8, в правой границе указывают 9. Так устроен цикл for: он последовательно берёт значения диапазона и выполняет вложенные команды. Сам цикл подробно рассматривается в уроке мини-курса Python о цикле for и диапазоне.

Команда print выводит значение на экран. Поэтому сначала проверим сам диапазон без дополнительных условий: каждая строка покажет очередное число.

for number in range(4, 9):    print(number)  # по одному в строке: от 4 до 8
Разберём на примере
Посчитайте значения в отрезке
Сколько целых чисел содержит отрезок от 12 до 15 включительно?
  1. Первое число — 12, последнее — 15; оба входят в отрезок.
  2. Перечислим значения: 12, 13, 14 и 15.
  3. Их четыре. В Python для этого перебора нужна запись range(12, 16).

Делимость и остаток

Если при делении одного целого числа на другое не остаётся «лишней» части, первое число делится на второе нацело. Например, 18 делится на 6, потому что 18 можно составить из трёх шестёрок. Число, которое делят, называют делимым, а число, на которое делят, — делителем.

Python находит остаток от деления с помощью знака %. Если остаток равен нулю, деление было нацело. Поэтому проверку «число делится на 6» записывают как number % 6 == 0. Знак сравнения == спрашивает, равны ли значения; один знак = присваивает значение переменной. Арифметические знаки Python, включая остаток от деления, подробнее разобраны в уроке мини-курса об арифметических выражениях.

Команда if выполняет вложенные строки только тогда, когда проверка после неё верна. В примере она пропустит в print только числа, которые делятся на 6.

for number in range(10, 21):    if number % 6 == 0:        print(number)  # 12, затем 18
Разберём на примере
Найдите числа, делящиеся на четыре
Какие числа от 13 до 20 включительно делятся на 4 без остатка?
  1. Проверяем числа по порядку: 13, 14, 15, 16, 17, 18, 19 и 20.
  2. Только для 16 и 20 остаток при делении на 4 равен нулю.
  3. Ответ: 16 и 20. Для проверки каждого значения подходит условие number % 4 == 0.

Условия можно соединять словами and («и») и or («или»). При and должны выполниться обе проверки. При or достаточно хотя бы одной. Сначала проверяй каждую часть отдельно, а затем соединяй их.

Цифры десятичной записи

Запись числа 5082 состоит из цифр 5, 0, 8 и 2. Это десятичная запись: каждая позиция показывает, сколько в числе тысяч, сотен, десятков и единиц. В задачах могут попросить сложить цифры, проверить, встречается ли среди них ноль, или найти последнюю цифру. Само число и цифры его записи — связанные, но разные вещи.

Для вычислений удобно по очереди отделять последнюю цифру: остаток от деления на 10 — это последняя цифра, а целочисленное деление // 10 убирает её. У отрицательного числа сначала берём модуль: знак минус не является цифрой. При нуле цикл не сделает ни одного шага, и сумма цифр останется равна нулю. abs даёт модуль числа. Цикл while повторяет команды, пока условие верно. Запись digit_sum += digit прибавляет новую цифру к накопленной сумме; remaining //= 10 делит оставшуюся часть числа на 10 нацело и сохраняет результат. В каждом повторе отдельно запоминаем последнюю цифру и прибавляем её к сумме.

number = 5082remaining = abs(number)digit_sum = 0 while remaining > 0:    digit = remaining % 10    digit_sum += digit    remaining //= 10 print(digit_sum)  # 15

В каждом повторе мы отделяем одну цифру и уменьшаем оставшуюся часть числа, поэтому цикл заканчивается. Как отделять цифры и что делать с нулём и отрицательным числом, подробно разобрано в уроке о цифрах числа. Устройство цикла отдельно объясняется в уроке о цикле while.

Разберём на примере
Проследите отделение цифр
Найдите сумму цифр числа 7305.
  1. Сначала отделяем 5: остаток при делении 7305 на 10 равен 5; остаётся 730.
  2. Затем отделяем 0 и получаем остаток 73.
  3. Из 73 отделяем 3, затем из 7 — цифру 7. Складываем: 5 + 0 + 3 + 7 = 15.
  4. Ответ: 15. Порядок отделения идёт справа налево, но сумма от этого не меняется.

Натуральные и собственные делители

Для положительного числа можно перечислить числа, на которые оно делится нацело. Здесь натуральные числа — это 1, 2, 3 и все следующие положительные целые числа. Такие значения называют натуральными делителями исходного числа. У 18 это 1, 2, 3, 6, 9 и 18: каждое из них даёт остаток 0 при делении 18 на него.

Собственными делителями называют делители числа, кроме самого числа. Значит, у 18 собственные делители — 1, 2, 3, 6 и 9. Единицу включаем. Если условие просит сумму собственных делителей, складываем именно этот список и не добавляем 18.

Список в Python хранит несколько значений по порядку. Команда append добавляет значение в конец списка, а sum складывает все значения списка. Эти приёмы подробно разобраны в уроке Python о списках.

number = 18proper_divisors = [] for candidate in range(1, number):    if number % candidate == 0:        proper_divisors.append(candidate) print(proper_divisors)  # [1, 2, 3, 6, 9]print(sum(proper_divisors))  # 21

Правая граница цикла равна самому числу, но не входит в перебор: это сделано специально, ведь мы ищем собственные делители.

Разберём на примере
Отделите собственные делители
Перечислите собственные делители числа 12 и найдите их сумму.
  1. Начинаем с 1 и проверяем числа меньше 12.
  2. 12 делится без остатка на 1, 2, 3, 4 и 6.
  3. Число 12 тоже является натуральным делителем, но оно не собственное, поэтому его исключаем.
  4. Сумма собственных делителей равна 1 + 2 + 3 + 4 + 6 = 16.

Простые числа

У некоторых чисел список натуральных делителей особенно короткий. Например, у 7 есть только два таких делителя: 1 и 7. Число больше единицы, у которого ровно два натуральных делителя — единица и оно само, называется простым. Если делителей больше двух, число составное.

Единица не простая и не составная: у неё только один натуральный делитель. Ноль и отрицательные числа тоже не относятся к простым в этой теме. При проверке отдельного числа значения меньше 2 можно исключить заранее. В примере ниже мы всё же проверяем 1: подсчёт найдёт у неё один делитель, а условие «ровно два» не пропустит её в список простых. Оба способа дают правильный ответ.

Неверно
Единица — простое число, потому что она делится только на себя.
Как правильно
У простого числа ровно два натуральных делителя: 1 и оно само. У единицы только один делитель — она сама, поэтому 1 не простое и не составное число.
primes = []for number in range(1, 11):    divisor_count = 0    for candidate in range(1, number + 1):        if number % candidate == 0:            divisor_count += 1    if divisor_count == 2:        primes.append(number) print(primes)  # [2, 3, 5, 7]

Для каждого числа считаем его натуральные делители. Проверка divisor_count == 2 оставляет только простые. Это прямой и понятный способ для короткого диапазона; позже проверку можно ускорить, но сначала важно понять, что именно считает программа.

Разберём на примере
Решите, какие числа простые
Какие числа среди 8, 11 и 15 простые?
  1. У 8 есть делители 1, 2, 4 и 8 — их больше двух, значит число составное.
  2. У 11 только два делителя: 1 и 11. Значит, 11 простое.
  3. У 15 есть 1, 3, 5 и 15. Число 15 составное; ответ — 11.

Пары делителей и квадрат

Делители удобно искать парами. Если 4 делит 36, то и 9 делит 36, потому что 4 × 9 = 36. Для каждого найденного меньшего делителя сразу известен второй: нужно разделить исходное число на первый. Например, у 36 пары такие: (1, 36), (2, 18), (3, 12), (4, 9) и (6, 6).

Пока числа малы, можно проверить каждого возможного делителя по очереди. Но для 1 000 000 поиск собственных делителей таким способом потребует 999 999 проверок: от 1 до 999 999. Если в задаче нужно обработать тысячи чисел, длинный перебор повторится для каждого из них. Нам нужен способ не потерять делители и при этом проверить гораздо меньше кандидатов.

Два числа в каждой паре называют парными делителями. Квадратный корень из числа — это неотрицательное число, которое при умножении на себя даёт исходное. Например, квадратный корень из 36 равен 6, потому что 6 × 6 = 36. В любой паре делителей хотя бы один не больше квадратного корня: если бы оба были больше, их произведение тоже было бы больше исходного числа. Значит, достаточно проверить кандидатов до этой границы и для каждого найденного делителя сразу взять второй из пары.

Для 1 000 000 квадратный корень равен 1000: вместо 999 999 кандидатов проверим только числа от 1 до 1000. Если корень не целый, отдельного вычисления корня не нужно: проверяем кандидата, пока его квадрат не больше исходного числа. Так, для 50 проверка дойдёт до 7, потому что 7 × 7 = 49, а 8 × 8 = 64 уже больше 50. Если исходное число — квадрат, в середине получится пара из одинаковых значений. У 36 это (6, 6), и делитель 6 нужно посчитать один раз, а не два. Для чрезвычайно большого числа даже проверок до корня может оказаться много; тогда ищем, не помогает ли другое обязательное условие задачи сократить список проверяемых чисел.

Знак <= читается «меньше или равно». В цикле candidate += 1 означает «увеличить candidate на единицу». Знак != проверяет, что значения не равны. Поэтому условие paired != candidate отличает обычную пару от средней пары из одинаковых чисел.

number = 36divisors = []candidate = 1 while candidate * candidate <= number:    if number % candidate == 0:        paired = number // candidate        divisors.append(candidate)        if paired != candidate:            divisors.append(paired)    candidate += 1 print(divisors)  # [1, 36, 2, 18, 3, 12, 4, 9, 6]

Проверка candidate * candidate <= number останавливает цикл после середины пар и сравнивает только целые числа: для очень больших значений не нужно приближённо вычислять корень. Выражение number // candidate находит вторую часть пары: здесь деление всегда точное, потому что мы уже проверили делимость. В условии paired != candidate равная пара (например, 6 и 6) добавляется только один раз. Этот пример собирает все натуральные делители; если нужны только собственные, само число нужно исключить из результата.

Иногда нужны не все делители, а только те, которые отвечают ещё одному условию. Тогда проверяем каждое значение сразу после того, как нашли пару. Например, у 24 оставим собственные делители больше 5. Само число 24 исключаем, потому что собственным делителем оно не считается. Меньшее и большее значения проверяем отдельно: в паре (2, 12) подходит 12, хотя 2 не подходит.

number = 24selected = []candidate = 1 while candidate * candidate <= number:    if number % candidate == 0:        paired = number // candidate        if candidate > 5 and candidate < number:            selected.append(candidate)        if paired != candidate and 5 < paired < number:            selected.append(paired)    candidate += 1 print(selected)  # [12, 8, 6]

Получились 12, 8 и 6 — это все собственные делители 24, которые больше 5. Порядок в списке повторяет порядок найденных пар; вручную те же числа можно записать по возрастанию: 6, 8, 12. Проверка paired != candidate также защищает середину квадрата от повтора. Если задача просит только количество подходящих делителей, можно вместо списка увеличивать счётчик на единицу за каждое подходящее значение; если нужен наибольший — сравнивать каждое подходящее значение с текущим наибольшим.

Тот же вывод помогает при проверке простоты. Для числа больше 1 достаточно попробовать делители от 2 до квадратной границы. Если хоть один делит число без остатка, число составное: его второй делитель уже известен. Если не нашлось ни одного, кроме 1 и самого числа делителей нет, значит, число простое. Например, 91 не простое: проверка дойдёт до 7 и обнаружит пару (7, 13). Для 97 кандидаты от 2 до 9 не дают нулевого остатка; дальше искать не нужно, поэтому 97 простое. Так можно ускорить проверку множества чисел, даже если полный список их делителей не требуется.

Разберём на примере
Не посчитайте середину дважды
Сколько натуральных делителей у 49? Перечислите их.
  1. Пробуем делители от 1 до тех пор, пока их квадрат не станет больше 49.
  2. Пара для 1 — это 1 и 49; для 7 второй делитель тоже равен 7.
  3. Делители: 1, 7 и 49. Число 7 встречается один раз, поэтому всего три делителя.
Неверно
Если меньший делитель пары не подошёл условию, можно пропустить всю пару.
Как правильно
Дополнительное условие проверяется отдельно для каждого значения. Например, в паре (2, 12) число 2 может не подойти, а 12 — подойти. Пара сообщает, что оба значения являются делителями, но не делает их одинаковыми по смыслу.

Знак вопроса в записи числа

В условии иногда дана запись числа с неизвестными цифрами, например 2??. Каждый знак вопроса здесь обозначает одну десятичную цифру, а не любое количество символов. Поэтому у такой маски ровно сто вариантов: десять цифр для разряда десятков и десять для разряда единиц. Здесь первая цифра уже задана — это 2. Если бы вместо неё стоял вопросительный знак, ноль пришлось бы исключить: запись должна оставаться трёхзначным числом.

Запись с неизвестными местами назовём маской. Для перебора вставляем вместо каждого вопросительного знака цифры от 0 до 9, получаем целые числа и проверяем требование задачи. Для этого удобно вложить один цикл в другой: для каждой цифры десятков перебрать все цифры единиц. Каждый внутренний проход дописывает одну цифру, поэтому образуются все сочетания без пропусков. Цифры сначала записаны как текст. В записи "0123456789" цикл по очереди возьмёт каждый символ. Знак + соединяет эти части, а функция int превращает готовую запись в целое число.

В других условиях маска может содержать и звёздочку *. В ней звёздочка обозначает любое количество цифр, даже ни одной. Например, маске 3*5 подходят 35, 305 и 3005. Знак вопроса устроен иначе: маске 3?5 подходит 305, но не 35 и не 3005. Всегда прочитай определение знаков в самом условии. В практике ты решишь задачу с двумя знаками вопроса; звёздочку разберём здесь на небольшом примере.

matches = []for tens in "0123456789":    for units in "0123456789":        number = int("2" + tens + units)        if number % 25 == 0:            matches.append(number) print(matches)  # [200, 225, 250, 275]

В этом примере проверяется делимость на 25. Среди чисел, которые заканчиваются на 00, 25, 50 или 75, проходят ровно четыре: 200, 225, 250 и 275. Внутренний цикл полностью завершает перебор единиц для каждой цифры десятков, затем внешний переходит к следующей цифре.

Сначала оцени число вариантов. У маски 2?? их всего 10 × 10 = 100, поэтому удобно сразу подставить цифры. У маски 2???? первая цифра тоже задана, а четыре вопросительных знака дают уже 10 × 10 × 10 × 10 = 10 000 вариантов. Если первый знак тоже вопросительный, ноль на этом месте исключаем: маска ???? задаёт 9 000 четырёхзначных чисел. Перебирать все числа до очень большой правой границы было бы расточительно, когда фиксированные цифры заранее исключают почти все числа. В таком случае строим только записи по маске, а затем проверяем делимость или нужный остаток. Если, наоборот, условие допускает только кратные заданному числу, можно заранее перебирать только их; выбор зависит от того, какой список кандидатов короче.

Ноль внутри записи допустим: из 7*2 можно получить 702. Но ведущий ноль не превращает запись в новое многозначное число: 025 — это запись числа 25, а не трёхзначное число. Для звёздочки особенно важна верхняя граница. Если по условию число не больше 800, маска 7*2 допускает пустую вставку (72) или одну цифру (от 702 до 792). Две вставленные цифры дали бы как минимум 7002 — уже больше 800. Значит, бесконечное на вид число вариантов на деле ограничено условием задачи.

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

middles = [""]for digit in "0123456789":    middles.append(digit) matches = []for middle in middles:    number = int("7" + middle + "2")    if number <= 800 and number % 9 == 0:        matches.append(number) print(matches)  # [72, 702, 792]

Проверим ответ независимо: 72 делится на 9, потому что 72 = 9 × 8. Среди трёхзначных записей 702 и 792 тоже делятся на 9; для остальных проверка остатка даст не ноль. Если граница станет больше и разрешит две цифры вместо звёздочки, нужно добавить в перебор все пары цифр, включая 00 и 09. При двух звёздочках общую допустимую длину распределяют между ними, но сначала снова выводят её из границы числа. Без верхней границы у звёздочки было бы бесконечно много возможных вставок, поэтому начинать такой перебор без ограничения нельзя.

Разберём на примере
Проверьте вторую маску
Какие числа можно получить из маски 4?? и какие из них делятся на 25?
  1. Оба вопросительных знака могут быть любыми цифрами от 0 до 9, поэтому маска даёт все числа от 400 до 499 включительно.
  2. Сначала перечисляем последние две цифры, которые делятся на 25: 00, 25, 50 и 75.
  3. Добавляем к каждой записи неизменную цифру сотен 4.
  4. Подходят 400, 425, 450 и 475. Для каждого числа из маски проверка остатка дала бы ноль.

Если к маске добавлено условие чётности, смотрим на последнюю цифру. Число чётное, когда оно делится на 2 без остатка: последняя цифра тогда равна 0, 2, 4, 6 или 8. Все десятки делятся на 2, поэтому остальные цифры на чётность не влияют. В записи 3?5? последняя позиция может быть только одной из этих пяти цифр, а другое условие всё равно проверяем отдельно.

На экзамене

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

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

Практика

Практика временно недоступна. Можно продолжить читать теорию.

Итог

Что получилось

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

Начинай с точного чтения границ и слов «собственный», «ровно» и «первые». Затем проверь алгоритм на небольшом диапазоне и вручную пересчитай найденные делители и итог. Если ответ не сходится, вернись к разделу о парах или границах и проверь один кандидат по шагам.

Уроки Python о цикле for и диапазоне, цикле while, списках и целых числах и выражениях поясняют нужный синтаксис. Это ссылки на конкретные приёмы, а не обязательный маршрут: весь курс до этой темы проходить не требуется.

Проверьте себя
Как записать в range перебор всех целых чисел от 7 до 12 включительно?
range(7, 13): правая граница не входит в перебор, поэтому указываем число на единицу больше 12.
Что сообщает проверка number % 5 == 0?
Остаток при делении number на 5 равен нулю, значит number делится на 5 нацело.
Как цикл отделения цифр обработает число 0?
Тело while remaining > 0 не запустится, а сумма останется равной 0 — это правильная сумма цифр числа 0.
Входит ли само число в список собственных делителей? А единица?
Само число исключают; 1 включают для чисел больше 1. У единицы собственных натуральных делителей нет.
Почему 1 не является простым числом?
У числа 1 только один натуральный делитель. У простого числа их ровно два: 1 и оно само.
Сколько раз нужно учитывать делитель 8 при поиске делителей числа 64 парами?
Один раз: 8 и 8 образуют единственную среднюю пару квадрата.
Если меньшая часть пары не прошла дополнительное условие, можно ли пропустить большую?
Нет. Проверяй обе части независимо: большая может подойти даже тогда, когда меньшая нет.
Сколько вариантов даёт один знак вопроса в маске числа?
Десять цифр от 0 до 9. Если знак стоит первым в многозначном числе, ноль обычно исключают как ведущий.
Сколько цифр может стоять вместо звёздочки в маске 7*2, если число не больше 800?
Ноль или одна цифра: 72 и числа от 702 до 792 укладываются в границу; две цифры дали бы как минимум 7002.
Что нужно сделать после поиска первых подходящих чисел в большом диапазоне?
Независимо проверить границы, делители каждого кандидата, порядок первых результатов и вычисление итогового ответа.