65 lines
1.8 KiB
Racket
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)))
|