advent-of-code/2020/day09/day09.rkt
2024-11-12 21:46:18 +01:00

65 lines
1.8 KiB
Racket

#lang racket
(module+ test
(require rackunit))
(module+ main
(displayln "Day 9"))
(define (read-input filename)
(list->vector (map string->number (file->lines filename))))
(define (initial-state p m)
(reverse (for/list ([x (in-vector p 0 m)])
(for/list ([y (in-vector p 0 m)]
#:unless (= x y))
(+ x y)))))
(define (update-state s p k)
(define m (length (car s)))
(define new-sums (for/list ([x (in-vector p (- k m) k)])
(+ x (vector-ref p k))))
(append (cdr s) (list new-sums)))
(define (in-state? s x)
(member x (flatten s)))
;; The initial state is computed in O(m^2), and the search itself is
;; only O(nm), where n is the length of the input, because updating
;; the state is linear in m. So the overall complexity is O(m^2 + nm)
;; instead of O(nm^2) for the naïve solution.
(define (find-invalid-number p m)
(define-values (s x)
(for/fold ([s (initial-state p m)]
[x (vector-ref p m)])
([k (in-naturals m)]
#:break (not (in-state? s x)))
(values (update-state s p k)
(vector-ref p k))))
x)
(define (part1 filename m)
(find-invalid-number (read-input filename) m))
(module+ test
(check-equal? (part1 "test" 5) 127))
(module+ main
(displayln (part1 "input" 25)))
(define (part2 filename m)
(define p (read-input filename))
(define n (vector-length p))
(define invalid (find-invalid-number p m))
(for*/last ([width (in-range 2 n)]
[i (in-range 0 (- n width))])
(define contiguous (vector->list (vector-copy p i (+ i width))))
#:final (= invalid (apply + contiguous))
(+ (apply min contiguous)
(apply max contiguous))))
(module+ test
(check-equal? (part2 "test" 5) 62))
(module+ main
(displayln (part2 "input" 25)))