Последовательность из файла
В файле список чисел, надо перебрать пары или тройки подряд идущих и проверить условие. Чтение файла и цикл здесь всегда одни и те же.
- 1Что проверяет номер
- 2Чтение файла
- 3Пары
- 4Тройки
- 5Оканчивается на…
- 6Дополнения
- 7Пример с abs и максимумом до цикла
- 8Как решать
- 9Ловушки
- 10Домашка
Что проверяет номер
Представь окно, которое едет по списку чисел: в нём сначала первое и второе число, потом второе и третье и так далее. Соседние окна пересекаются, и это важно: пара из второго и третьего числа считается, даже если второе уже было в предыдущей паре.
Файл с последовательностью чисел. Проходим окном из двух или трёх соседних элементов, отбираем окна по условию. В ответ два числа: сколько окон подошло и наибольшая (или сумма) из каких-то значений.
Чтение файла
Эта строка одна на все задачи номера, меняется только имя файла. После неё в a лежит обычный список чисел.
a = [int(line) for line in open('17_23757.txt')]
Каждая строка файла — одно число. Разделитель \r вместо \n тоже работает: Python читает файл как текст и понимает оба.
Разберём запись по частям:
open('файл')открывает файл, а циклfor line in ...выдаёт его строку за строкой;- в
lineлежит текст вроде'105\n', аint(line)превращает его в число и сам убирает перевод строки; - квадратные скобки собирают все числа в список.
Запись длинная только с виду. Вот то же самое обычным циклом, а рядом учебный файл 17-demo.txt, чтобы сразу запустить:
a = [] for line in open('17-demo.txt'): a.append(int(line)) print(len(a)) print(a[:5])
Пары
Перед циклом считаем всё, что относится ко всей последовательности, а в цикле проверяем соседей. В примере минимальное двузначное считается один раз, до цикла.
a = [int(line) for line in open('17_23757.txt')] c = [] mn = min(x for x in a if 10 <= x <= 99) # минимальное двузначное for i in range(len(a) - 1): # до предпоследнего идём if (10 <= a[i] <= 99) + (10 <= a[i + 1] <= 99) == 1: # ровно одно двузначное if (a[i] + a[i + 1]) % mn == 0: c.append(a[i] + a[i + 1]) print(len(c), max(c))
Условие считаем сложением: True + False == 1. «Ровно два из трёх» — == 2, «хотя бы одно» — >= 1 (или or).
Весь путь на учебном файле
Условие: пары соседних чисел, где ровно одно двузначное, а сумма делится на 3. Нужны количество таких пар и наибольшая сумма. Несколько пар из файла:
| a[i] | a[i + 1] | сумма | подходит |
|---|---|---|---|
| 3572 | 278 | 3850 | нет |
| 240 | -84 | 156 | да |
| -84 | 672 | 588 | да |
| 672 | -46 | 626 | нет |
Проверь каждую строку сам: сколько чисел двузначные и делится ли сумма на 3.
a = [int(line) for line in open('17-demo.txt')] c = [] for i in range(len(a) - 1): x, y = a[i], a[i + 1] good = (10 <= abs(x) <= 99) + (10 <= abs(y) <= 99) if good == 1 and (x + y) % 3 == 0: c.append(x + y) print(len(c), max(c))
Почему len(a) - 1? В списке из 5 чисел пар всего 4. Если дойти до последнего индекса, a[i + 1] выйдет за конец списка и будет ошибка.
Почему складываем условия? Python считает True за 1, а False за 0. Значит, сумма условий равна числу выполненных. Это короткая запись для «ровно одно из двух».
Дан список a = [12, -7, 25, 40, 33, -18, 9, 57, -21, 16, 70, 27]. Найди число пар соседних элементов, сумма которых делится на 3, и наибольшую такую сумму. Запиши два числа через пробел.
# пиши решение здесь
Подсказка
Список можно вставить в редактор прямо как есть.
Разбор на коротком списке
Возьмём [5, 12, 7]. Пар всего две: 5 и 12, 12 и 7. Поэтому цикл идёт по range(len(a) - 1), то есть i равно 0 и 1. Число 12 участвует в обеих парах, это нормально.
| в условии | в коде |
|---|---|
| ровно одно из двух | (усл1) + (усл2) == 1 |
| хотя бы одно | усл1 or усл2 |
| оба | усл1 and усл2 |
| двузначное, с учётом минуса | 10 <= abs(x) <= 99 |
| кратно 7 | x % 7 == 0 |
Дан список a = [105, -12, 47, 8, -99, 64, 31, -250, 73, 16]. Найди число пар соседних, где ровно одно число двузначное (знак не учитываем), и наибольшую сумму такой пары. Запиши два числа через пробел.
# пиши решение здесь
Подсказка
10 <= abs(x) <= 99.
Тройки
Тройки устроены так же, только индексов три, а цикл заканчивается на одну позицию раньше. Удобно сразу назвать элементы x1, x2, x3.
a = [int(x) for x in open('17_23949.txt')] def f(x): return str(x)[0] == str(x)[-1] # первая цифра = последней def p(x): return 10000 <= x <= 99999 and str(x)[-4:] == '1717' # пятизначное, оканчивается на 1717 (пример) c = [] for i in range(len(a) - 2): x1, x2, x3 = a[i], a[i + 1], a[i + 2] if f(x1) + f(x2) + f(x3) == 1: if p(x1) + p(x2) + p(x3) == 2: c.append(max(x1, x2, x3)) print(len(c), sum(c))
Что считать в ответ (max, sum, сумма тройки) зависит от условия. Условия оформляем функциями f, p.
Для того же списка a = [12, -7, 25, 40, 33, -18, 9, 57, -21, 16, 70, 27] найди число троек соседних элементов, в которых ровно два чётных числа, и наибольшую сумму такой тройки. Запиши два числа через пробел.
# пиши решение здесь
Подсказка
Отрицательные чётные тоже чётные: x % 2 == 0 работает и для них.
Оканчивается на…
Отрицательные числа есть почти в каждом файле, поэтому привычка писать abs спасает от потери балла.
Проверка «оканчивается на 152», два способа:
abs(x) % 1000 == 152(abs— модуль, абсолютное значение);str(x)[-3:] == '152'.
«В числе есть тройка»: '3' in str(x).
Дополнения
Эти две функции встречаются часто. Их можно просто вставлять в начало решения.
Простое число:
def p(x): return x > 1 and all(x % d != 0 for d in range(2, int(x ** 0.5) + 1))
Цифры идут по возрастанию, без повторов:
def up(x): return str(x) == ''.join(sorted(str(x))) and len(str(x)) == len(set(str(x)))
Для 147 истинно, для 122 ложно (повтор) и для 174 ложно. ''.join(...) склеивает отсортированные цифры обратно в строку: без него строку нельзя сравнить со списком.
Дан список a = [11, 4, 13, 9, 17, 6, 23, 20, 5, 8]. Найди число троек соседних, где ровно два простых числа, и наибольшую сумму такой тройки. Запиши два числа через пробел.
# пиши решение здесь
Подсказка
Возьми функцию p выше.
Пример с abs и максимумом до цикла
Здесь собрано всё сразу: максимум с особым свойством, модуль и тройки.
a = [int(x) for x in open('17.txt')] mx = max(x for x in a if str(x)[-2:] == '30') # максимум, оканчивающийся на 30 m = [] for i in range(len(a) - 2): x1, x2, x3 = a[i], a[i + 1], a[i + 2] if len(str(abs(x1))) != 4: # abs: число без знака минус if (x1 + x2 + x3) > mx: m.append(x1 + x2 + x3) print(len(m), max(m))
Максимум считаем до цикла, один раз по всей последовательности.
Для списка a = [12, -7, 25, 40, 33, -18, 9, 57, -21, 16, 70, 27] найди наибольшее число, модуль которого оканчивается на 7. Затем посчитай тройки соседних, сумма которых больше этого числа, и наибольшую такую сумму. Запиши два числа через пробел.
# пиши решение здесь
Подсказка
Максимум считаем до цикла, один раз.
Как решать
Этот порядок подходит для любой задачи номера.
- Читаем файл.
- До цикла считаем «глобальное»: минимум, максимум с особым свойством, количество кратных.
- Условия окна оформляем функциями.
- Цикл
range(len(a) - 1)для пар иrange(len(a) - 2)для троек. - Подходящие значения в список
c, в ответlen(c)иmax(c)илиsum(c).
Ловушки
Цикл до len(a) - 1 для пар и len(a) - 2 для троек, иначе выйдешь за конец списка.
Для знака и количества цифр отрицательного числа: len(str(abs(x))). Просто str(x) посчитает минус как символ.
Оканчивается на: str(x)[-3:] читает цифры без знака сам. А x % 1000 у отрицательных даёт другое число (-1152 % 1000 = 848), поэтому используем abs(x) % 1000.
Максимум и минимум — до цикла.
Скобки: (a < x < b) + (c < y < d) == 1.
Домашка
Задачи с настоящих экзаменов и из банка ФИПИ. Решай прямо здесь: кнопка «Решать здесь» открывает редактор, а код каждой задачи сохраняется.
Задачи «Попробуй сам» учебные, в домашке задачи с настоящих экзаменов и из банка ФИПИ. Код в блоках можно менять и запускать, он выполняется прямо в браузере.