Add: add optimized solution for second day tasks
This commit is contained in:
parent
1cc4e213d7
commit
ff470788b0
1 changed files with 164 additions and 0 deletions
164
python/src/2-day/optimized_solution.py
Normal file
164
python/src/2-day/optimized_solution.py
Normal file
|
|
@ -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()
|
||||
Loading…
Add table
Add a link
Reference in a new issue