Этот пост изначально появился на steadbytes.com.
Полное решение можно найти на Гадость
Часть первая
Учитывая Ввод головоломки претензии нам просят найти Количество квадратных дюймов ткани в течение двух или более претензий Отказ
- Разбирайте ввод в последовательность претензий ткани
- Для каждого квадратного дюйма ткани найдите количество претензий, содержащих его
- Подсчитать общее количество квадратных дюймов ткани, где счет претензии больше, чем один
Разборка ввода
Каждая строка ввода представляет собой претензию в следующем формате:
#@ , : x
Например, # 123 @ 3,2: 5x4
Соответствует прямоугольнику с ID 123
, 3
С левого края 2
дюймы с верхнего края, 5
дюймов в ширину и 4
дюймов.
- Разделить вход в новинки
- Для каждой строки извлечь данные об утверждении:
- Я БЫ
- Расстояние от левого края
- Расстояние от верхнего края
- Ширина
- Высота
Извлечение данных претензий могут быть достигнуты с помощью A Регулярное выражение :
import re claim_re = re.compile( r"#(?P<_id>[0-9]+) @ " r"(?P[0-9]+),(?P [0-9]+): " r"(?P [0-9]+)x(?P [0-9]+)" ) m = claim_re.match("#123 @ 3,2: 5x4") # retrieve all cptured values m.groups() # -> ('123', '3', '2', '5', '4') # retreieve a specific captured value m.groups('_id') # -> '123'
- Python названные группы захвата Используются для изготовления экстрагированных кусков данных.
- Интерактивная демо и объяснение этого регулярного выражения
Извлеченные значения из регулярного выражения – это строки, однако для этой головоломки они представляют целые числа. Кроме того, после извлеченных значений регулярная экспрессия объекта совпадения не требуется, и претензия может быть представлена собственным объектом. Так как это Python, A Дикт
сделаю трюк!
Учитывая претензию от ввода головоломки:
- Сопоставьте каждое значение, используя
Prec_re
регулярное выражение - Создать
Дикт
Там, где клавиши являются именами групп, а значения – это извлеченные строки, припаренные к целым числам:
def parse_claim(claim_string): m = claim_re.match(claim_string) return {k: int(v) for k, v in m.groupdict().items()} parse_claim("#123 @ 3,2: 5x4") # {'_id': 123, 'left': 3, 'top': 2, 'width': 5, 'height': 4}
Представляющий ткань
Для этой головоломки ткань можно рассматривать как сетку, где каждая координата представляет квадратный дюйм ткани и содержит целое число, обозначающее количество претензий на него. Учитывая единственное требование в предыдущем примере:
00000000000 00000000000 00011111000 00011111000 00011111000 00011111000 00000000000 00000000000 00000000000
Для каждого претензии:
- Найти «физическую» площадь (координаты в сетке), она будет покрывать
- Увеличить соответствующее количество претензий в ткани
Найти область, представленную претензию, может быть достигнута с использованием позиций (левый, верхний) и размеры (ширина, высота), извлеченные из ввода головоломки:
def claim_area(claim): return ( (i, j) for i in range(claim["left"], claim["left"] + claim["width"]) for j in range(claim["top"], claim["top"] + claim["height"]) )
Эта функция принимает претензию Дикт
производится предыдущим parse_claim
Функция и возвращает Генератор который дает пары (х, у)
Координаты в тканевой сетке, которая сводится в пределах претензии.
Наиболее интуитивно понятный способ представления ткани сетки с использованием структуры 2D массива:
fabric = [] for y in range(height_of_fabric): row = [] for x in range(width_of_fabric): row.append(0) fabric.append(row) # to update the fabric counters for a claim for x, y in claim_area("#123 @ 3,2: 5x4"): fabric[y][x] += 1
Однако нам на самом деле нам не нужна информация, представленная структурой всей ткани – только количество претензий, присутствующих на каждый квадратный дюйм. Кроме того, мы на самом деле не знаем точного размера ткани для использования в качестве пределов для структуры массива. Вопрос только дает нижнюю границу:
Весь кусок ткани, на которой они работают, это очень большой квадрат – по крайней мере 1000
дюймов на каждой стороне.
Чтобы избежать ненужных накладных расходов на строительство и итерацию по сравнению с большим 2D-массивом, мы можем использовать словарь, в котором ключи являются координатами, а значения – количество претензий на эту позицию:
fabric = {} # to add a claim for coord in claim_area("#123 @ 3,2: 5x4"): if coord in fabric: fabric[coord] += 1 else: fabric[coord] = 1 fabric[(3, 2)] # -> 1
С этим улучшением мы больше не храним значения для позиций в ткани без претензий. Подсчет ценностей в словаре, подобное это – это общая операция, а как таковая, Python включает в себя встроенный Счетчик
Структура данных в Коллекции модуль. Учитывая список претензии
Создание каждого претензии, проанализированной от ввода головоломки, вся ткань может быть представлена как таковая:
fabric = Counter(coord for claim in claims for coord in claim_area(claim)) fabric[(3, 2)] # -> number of claims at position (3, 2)
Нахождение перекрывающихся претензий
Вооружен нашим ткань
Нахождение количества квадратных дюймов в течение двух или более претензий требует подсчета общего количества значений в ткань
которые больше 1:
def part_1(fabric): return sum([1 for claim_count in fabric.values() if claim_count > 1])
Для моей ввода головоломки результат – 115348 Отказ
Часть 2
Далее нам говорят, что есть одинокий претензия, который не имеет совпадающих с любыми другими и просят найти ID указанного претензии.
Эта претензия будет иметь счетчик Country of 1
Для каждого из координат, содержащихся в нем в ткань
Отказ
- ИТЕРТЬ НА КАЖЕ ПРЕТЕНЗИИ
- Получить счетчик счетчиков от
ткань
каждой координаты в пределах претензии - Если каждое значение равно
1
вернуть идентификатор претензии
def part_2(claims, fabric): for claim in claims: # all returns True if and only if each value is True if all(fabric[coord] == 1 for coord in claim_area(claim)): return claim["_id"]
Для моей ввода головоломки результат – ID 188 Отказ
Ресурсы
Оригинал: “https://dev.to/steadbytes/aoc-2018-day-3-no-matter-how-you-slice-it-4afo”