From ff470788b0ae2638d828abbd4e29cb3a74dbfb66 Mon Sep 17 00:00:00 2001 From: geekiot Date: Tue, 2 Dec 2025 13:39:34 +0500 Subject: [PATCH] Add: add optimized solution for second day tasks --- python/src/2-day/optimized_solution.py | 164 +++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 python/src/2-day/optimized_solution.py diff --git a/python/src/2-day/optimized_solution.py b/python/src/2-day/optimized_solution.py new file mode 100644 index 0000000..b6dccff --- /dev/null +++ b/python/src/2-day/optimized_solution.py @@ -0,0 +1,164 @@ +""" +Оптимизированное решение для задачи дня 2: Подарочный магазин + +Основная идея оптимизации: +Вместо перебора всех чисел в диапазонах (что может быть очень медленно для больших диапазонов), +мы генерируем только числа нужной формы и проверяем, попадают ли они в заданные диапазоны. + +Для части 1: числа вида S+S (дважды повторяющаяся последовательность) +Для части 2: числа вида S+S+...+S (k раз, k >= 2) +""" + +from typing import List, Tuple, Set + + +def parse_ranges(input_str: str) -> List[Tuple[int, int]]: + """Парсит строку с диапазонами вида 'start-end,start2-end2'""" + ranges = [] + for part in input_str.strip().split(","): + if part: # пропускаем пустые части + start, end = map(int, part.split("-")) + ranges.append((start, end)) + return ranges + + +def is_in_ranges(number: int, ranges: List[Tuple[int, int]]) -> bool: + """Проверяет, находится ли число в одном из диапазонов""" + # Сортируем диапазоны для оптимизации (можно использовать бинарный поиск) + # Но для небольшого количества диапазонов линейный поиск тоже эффективен + for start, end in ranges: + if start <= number <= end: + return True + return False + + +def generate_repeated_numbers_part1(max_len: int = 10) -> Set[int]: + """ + Генерирует все числа вида S+S для части 1 + + Аргументы: + max_len: максимальная длина числа (по умолчанию 10, так как в input.txt + максимальная длина числа около 10-11 цифр) + + Возвращает: + Множество чисел вида S+S (например, 55, 6464, 123123) + """ + result = set() + + # Длина повторяющейся последовательности S + for s_len in range(1, max_len // 2 + 1): + # Генерируем все возможные S от 10^(s_len-1) до 10^s_len - 1 + start = 10 ** (s_len - 1) if s_len > 1 else 0 + end = 10**s_len + + for s in range(start, end): + # Пропускаем числа, начинающиеся с 0 (кроме самого 0) + if s == 0 or str(s)[0] != "0": + repeated = int(str(s) * 2) + if len(str(repeated)) <= max_len: + result.add(repeated) + + return result + + +def generate_repeated_numbers_part2(max_len: int = 10) -> Set[int]: + """ + Генерирует все числа вида S*k (k >= 2) для части 2 + + Аргументы: + max_len: максимальная длина числа + + Возвращает: + Множество чисел вида S*k (например, 12341234, 123123123, 1111111) + """ + result = set() + + # Длина повторяющейся последовательности S + for s_len in range(1, max_len // 2 + 1): + # Генерируем все возможные S + start = 10 ** (s_len - 1) if s_len > 1 else 0 + end = 10**s_len + + for s in range(start, end): + # Пропускаем числа, начинающиеся с 0 (кроме самого 0) + if s == 0 or str(s)[0] != "0": + s_str = str(s) + + # Количество повторений k (минимум 2) + for k in range(2, max_len // s_len + 1): + repeated_str = s_str * k + if len(repeated_str) <= max_len: + repeated = int(repeated_str) + result.add(repeated) + + return result + + +def solve_part1(ranges: List[Tuple[int, int]]) -> int: + """ + Решение части 1: сумма чисел вида S+S в диапазонах + + Оптимизация: + - Генерируем все возможные числа нужной формы заранее + - Проверяем только их принадлежность диапазонам + - Используем множество для быстрого поиска (хотя в данном случае это не критично) + """ + # Определяем максимальную длину числа в диапазонах + max_number = max(end for _, end in ranges) + max_len = len(str(max_number)) + + # Генерируем все числа вида S+S + candidates = generate_repeated_numbers_part1(max_len) + + # Суммируем только те, что попадают в диапазоны + total = 0 + for number in candidates: + if is_in_ranges(number, ranges): + total += number + + return total + + +def solve_part2(ranges: List[Tuple[int, int]]) -> int: + """ + Решение части 2: сумма чисел вида S*k (k >= 2) в диапазонах + + Оптимизация: + - Генерируем все возможные числа нужной формы заранее + - Проверяем только их принадлежность диапазонам + - Избегаем перебора миллионов чисел в диапазонах + """ + # Определяем максимальную длину числа в диапазонах + max_number = max(end for _, end in ranges) + max_len = len(str(max_number)) + + # Генерируем все числа вида S*k (k >= 2) + candidates = generate_repeated_numbers_part2(max_len) + + # Суммируем только те, что попадают в диапазоны + total = 0 + for number in candidates: + if is_in_ranges(number, ranges): + total += number + + return total + + +def main(): + # Чтение входных данных + with open("./src/2-day/input.txt", "r") as file: + input_str = file.read().strip() + + ranges = parse_ranges(input_str) + + # Решение части 1 + result1 = solve_part1(ranges) + print(f"Часть 1 (сумма чисел вида S+S): {result1}") + + # Решение части 2 + result2 = solve_part2(ranges) + print(f"Часть 2 (сумма чисел вида S*k, k>=2): {result2}") + + +if __name__ == "__main__": + main()