$ sudo teach IT
Модуль 4 · Циклы · Урок 4.5

Практикум: циклы

Восемь задач на while и for, чтобы закрепить приёмы модуля и увидеть, где новички обычно спотыкаются.

Практика~40 минутНовичок

За четыре урока вы разобрали while, break с continue и else, for с range() и вложенные циклы. По отдельности каждая тема выглядит понятной, но на реальной задаче конструкции нужно комбинировать: решить, какой цикл выбрать, сколько раз он повторится и что делать, если условие вообще ни разу не сработает. Этот урок без новой теории — здесь только разбор частых ошибок модуля и восемь задач, где всё изученное встречается вместе.

Частые ошибки модуля

Забыли изменить переменную в while — вечный цикл

i = 1
while i <= 5:
    print(i)
Программа зависает. Условие i <= 5 проверяется заново перед каждым повтором, а i внутри тела никогда не меняется — значит, оно всегда истинно. Правило простое: у каждого while внутри тела должна быть строка, которая двигает переменную из условия к завершению, обычно i += 1.

Путают границы range()

for i in range(1, 5):
    print(i)
Не ошибка, но частая неожиданность: выведет 1, 2, 3, 4, а не 5. Второе число range() в перебор не входит. Если нужно дойти включительно до 5, границу указывают на единицу больше: range(1, 6).

continue вместо break, и наоборот

for i in range(1, 10):
    if i == 5:
        continue
    print(i)
continue лишь пропускает одну итерацию — число 5 не напечатается, но цикл дойдёт до 9. Если нужно было полностью остановить перебор при первом же совпадении — это break, а не continue. Перед тем как писать одно из двух, полезно проговорить словами: «пропустить этот шаг и жить дальше» — continue, «хватит, дальше не идём» — break.

Забыли, что внутри вложенного цикла свой счётчик

for i in range(1, 4):
    for j in range(1, 4):
        print(i, j)
    print(i)
Внутренний цикл каждый раз стартует заново, поэтому j для каждого i снова пробегает от 1 до 3. Отступ решает всё: строка print(i) стоит на уровне внешнего for, поэтому выполнится один раз на каждое значение i, уже после того как внутренний цикл полностью отработает.

Приём: накопитель вместо print на каждом шаге

Во многих задачах ниже результат — это не одно число, а несколько строк или чисел подряд (все простые до N, числа Фибоначчи). Печатать их по одному внутри цикла неудобно для проверки, поэтому чаще собирают ответ в одну переменную-строку и печатают её один раз в конце — это называют накоплением (переменная-аккумулятор).

result = ""
for i in range(1, 4):
    if result == "":
        result = str(i)
    else:
        result += " " + str(i)

print(result)
result = "" — пустая строка перед циклом: место, куда будем складывать ответ.
if result == "": — проверка «это первое число или уже есть предыдущие». Для первого числа пробел перед ним не нужен, для остальных — нужен, поэтому ветки разные.
result += " " + str(i) — к уже накопленному тексту добавляется пробел и следующее число, переведённое в строку функцией str().

Программа выведет 1 2 3. Этот же приём пригодится для чисел Фибоначчи и списка простых чисел дальше в задачах.

Что важно запомнить

У каждого while в теле должна быть строка, которая приближает переменную к концу условия, иначе — вечный цикл.
range(a, b) не включает b: чтобы дойти до числа включительно, границу берут на единицу больше.
continue пропускает один шаг и продолжает цикл, break останавливает цикл целиком.
Отступ определяет, какому циклу принадлежит строка — особенно важно во вложенных циклах.
Чтобы собрать несколько значений в один ответ, заведите переменную-накопитель (например, пустую строку) до цикла и пополняйте её на каждом шаге.
Деление числа на цифры делают через % 10 (последняя цифра) и // 10 (отбросить последнюю цифру) — приём пригодится в задачах на числа.

Проверьте себя

5 вопросов

Угадай число

Дана переменная secret = 80 — загаданное число. Напишите цикл, который на каждом шаге:

  • считывает число через input() и переводит в int, сохраняя в переменную guess;
  • увеличивает счётчик попыток attempts на 1;
  • печатает "Больше", если guess меньше secret;
  • печатает "Меньше", если guess больше secret;
  • печатает "Угадали!" и останавливается, если guess равен secret.

Например, если по очереди ввести 50, 75, 82, 80 — программа напечатает четыре строки: Больше, Больше, Меньше, Угадали!, а attempts станет равен 4.

Все простые числа до N

Дана переменная n = 30. Найдите все простые числа от 2 до n включительно и соберите их в переменную primes — строку, где числа записаны через пробел по возрастанию.

Число простое, если оно больше 1 и не делится без остатка ни на одно число от 2 до самого себя, кроме единицы и себя же. Для n = 30 ожидается primes = "2 3 5 7 11 13 17 19 23 29".

НОД по алгоритму Евклида

Даны переменные a = 48 и b = 18. Найдите их наибольший общий делитель по алгоритму Евклида и сохраните в переменную gcd.

Алгоритм: возьмите два числа x и y (изначально x = a, y = b). Пока y не равен 0, заменяйте x на y, а y — на остаток от деления x на y. Когда y станет равен 0, ответ — текущее значение x. Для 48 и 18 ответ 6.

Числа Фибоначчи до N

Дана переменная n = 100. Соберите в переменную result все числа Фибоначчи, не превышающие n, через пробел, начиная с 0.

Последовательность Фибоначчи начинается с 0 и 1, а каждое следующее число — сумма двух предыдущих: 0, 1, 1, 2, 3, 5, 8... Для n = 100 ожидается result = "0 1 1 2 3 5 8 13 21 34 55 89" (следующее число, 144, уже больше 100, поэтому его быть не должно).

Число-палиндром

Дана переменная number = 12321. Определите, является ли число палиндромом — то есть читается ли одинаково слева направо и справа налево — и сохраните результат (True или False) в переменную is_palindrome.

Разворачивать число нужно арифметикой, без превращения в строку: последнюю цифру числа даёт number % 10, а отбросить последнюю цифру можно через number // 10. Для number = 12321 ожидается is_palindrome = True.

Ромб из звёздочек

Дана переменная n = 4. Постройте ромб из звёздочек * высотой 2 * n - 1 строк и сохраните его в переменную result: строки разделены переносом \n, без переноса в конце последней строки.

Ромб растёт от 1 звезды до 2 * n - 1 звёзд, а затем убывает обратно до 1, и каждая строка выровнена пробелами по центру. Для n = 4 результат:

   *
  ***
 *****
*******
 *****
  ***
   *

Самая длинная серия одинаковых символов

Дана переменная s = "aaabccccdaa". Найдите длину самой длинной серии подряд идущих одинаковых символов и сохраните её в переменную max_run.

Перебирайте строку символ за символом циклом for, сравнивая каждый символ с предыдущим. Для "aaabccccdaa" самая длинная серия — четыре буквы c подряд, значит max_run = 4.

Число счастливых билетов

Билет считается «счастливым», если у него шесть цифр (от 000000 до 999999) и сумма первых трёх цифр равна сумме последних трёх. Дана переменная n = 200000. Посчитайте, сколько счастливых билетов среди номеров от 0 до n - 1, и сохраните результат в переменную count.

Цифры номера можно получить арифметикой, без превращения в строку: например, у номера 234567 первая цифра — 234567 // 100000, вторая — (234567 // 10000) % 10, и так далее до последней цифры 234567 % 10. Для n = 200000 ожидается count = 10120.