Advent of code 2024 - Dia 05 de 25
Conteúdo
O quinto dia do Advent of Code foi ontem 05/12/2024! Se você caiu aqui hoje pela primeira vez, não deixe de ler os posts sobre o Dia 1, Dia 2, Dia 3, e Dia 4!
Classifiquei o quinto problema como fácil (parte 1) e médio (parte 2).
Dicas#
-
O problema tem duas entradas, uma lista de regras e uma lista de atualizações.
-
As páginas presentes na lista de regras (X) devem ser impressas antes das páginas (Y). Como a mesma página X pode ter várias Y, as regras são um dicionário com chaves do tipo int e listas também do tipo int.
-
As atualizações são listas de inteiros simples.
-
Para verificar se as regras foram respeitadas, verifique se toda página presente na atualização obedece as regras.
-
Uma forma de ver a validação é verificar se a lista antes da página sendo verificada tem alguma outra página listada nas regras da mesma página. Você pode utilizar as regras de fatiamento de listas para criar uma sub-lista com os elementos anteriores da lista.
Por exemplo:
>>> L = [7, 8, 9]
>>> L[1:]
[8, 9]
>>> L[:2]
[7, 8]
>>> L[:1] + L[2:]
[7, 9]
>>>
Releia a parte de fatiamento de listas no capítulo 7 se necessário.
- A reordenação pode ser feita da mesma forma. Quando um elemento fora de ordem for encontrado, retire-o da lista, trocando a ordem do elemento errado com o elemento do livro de regras que deveria aparecer antes.
Exemplo com uma lista pequena:
>>> REGRA = {8: [7]}
>>> atualização = [7, 8, 9]
# Como p é o segundo elemento, índice 1, podemos trocar a ordem:
>>> REORDENADO = atualização[:0] + [8] + [atualização[0]] + atualização[2:]
[8, 7, 9]
-
Este tipo de problema confunde, pois a ordenação por ordem crescente prevalece e mesmo respeitando as regras, você pode ter a impressão que está incorreto.
-
Você pode utilizar uma função recursiva para reordenar a lista, uma vez que ao mudar um elemento, as regras devem ser novamente verificadas.
-
Parte 1: Fácil - exige um pouco de criatividade para combinar listas e dicionários.
-
Parte 2: Médio - a reordenação recursiva não é tão evidente.
Quanto de Python você precisa saber?#
Os capítulos se referem ao meu livro Introdução à Programação com Python.
- Listas, Dicionários - Capítulo 6
- Funções recursivas - Capítulo 8
Resposta#
from auxiliares import string_para_matriz_int, uma_lista_por_linha
ORDEM = """47|53
97|13
97|61
97|47
75|29
61|13
75|53
29|13
97|29
53|29
61|53
97|53
61|29
47|13
75|47
97|75
47|61
75|61
47|29
75|13
53|13"""
TESTE = """
75,47,61,53,29
97,61,53,29,13
75,29,13
75,97,47,61,53
61,13,29
97,13,75,29,47
"""
def constrói_regras(restrições: list[list[int]]) -> dict[int, list[int]]:
regras = {}
for x, y in restrições:
regras[x] = regras.get(x, []) + [y]
return regras
def constrói_restrições(ordem: str) -> list[list[int]]:
return string_para_matriz_int(ordem, separador="|")
def verifica_ordem(regras: dict[int, list[int]], atualização: list[int]) -> bool:
for p, pagina in enumerate(atualização):
if pagina in regras:
anteriores = atualização[:p]
for anterior in anteriores:
if anterior in regras[pagina]:
return False
return True
def reordena(regras: dict[int, list[int]], atualização: list[int]) -> bool:
for p, pagina in enumerate(atualização):
if pagina in regras:
anteriores = atualização[:p]
for i, anterior in enumerate(anteriores):
if anterior in regras[pagina]:
return reordena(
regras,
anteriores[:i]
+ [pagina]
+ anteriores[i:]
+ atualização[p + 1 :],
)
return atualização
def soma_paginas_do_meio(regras, atualizações):
s = 0
for atualização in atualizações:
if verifica_ordem(regras, atualização):
meio = (len(atualização)) // 2
s += atualização[meio]
return s
# Parte 1
regras_teste_parte_1 = constrói_regras(constrói_restrições(ORDEM))
m_teste = string_para_matriz_int(TESTE, ",")
teste_parte_1 = soma_paginas_do_meio(regras_teste_parte_1, m_teste)
print("Teste parte 1:", teste_parte_1)
assert teste_parte_1 == 143
regras_parte_1 = constrói_regras(uma_lista_por_linha("05/regras.txt", separador="|"))
atualizações_parte_1 = uma_lista_por_linha("05/atualizacoes.txt", separador=",")
parte_1 = soma_paginas_do_meio(regras_parte_1, atualizações_parte_1)
print("Parte 1:", parte_1)
assert parte_1 == 5268
# Parte 2
soma_teste_parte_1 = soma_paginas_do_meio(
regras_teste_parte_1,
[
reordena(regras_teste_parte_1, atualização)
for atualização in m_teste
if not verifica_ordem(regras_teste_parte_1, atualização)
],
)
print("Soma dos elementos do meio, parte 2 vetor de teste:", soma_teste_parte_1)
assert soma_teste_parte_1 == 123
soma_parte_2 = soma_paginas_do_meio(
regras_parte_1,
[
reordena(regras_parte_1, atualização)
for atualização in atualizações_parte_1
if not verifica_ordem(regras_parte_1, atualização)
],
)
print("Soma dos elementos do meio, parte 2:", soma_parte_2)
assert soma_parte_2 == 5799
# Saída
# Teste parte 1: 143
# Parte 1: 5268
# Soma dos elementos do meio, parte 2 vetor de teste: 123
# Soma dos elementos do meio, parte 2: 5799