@@ -15,6 +15,9 @@ import (
1515// Then I found the line in the problem that says adjacent coordinates are
1616// on the same column or row, which made boundary calculations easier.
1717
18+ // Edit: Found a faster solution using slice bounds instead of a map
19+ // TODO:<Perf> Add performance from M1 Mac for old solution and new
20+
1821func main () {
1922 fmt .Println ("Part 1: " , part1 ("input.txt" ))
2023 fmt .Println ("Part 2: " , part2 ("input.txt" ))
@@ -53,7 +56,7 @@ type Rectangle struct {
5356func part2 (name string ) (largestArea int ) {
5457 lines := files .ReadLines (name )
5558 coords := createCoordinates (lines )
56- boundaries := createBoundaries (coords )
59+ bounds , minY := createBoundariesSlice (coords )
5760
5861 // Create all rectangles first. Might be bad for
5962 // performance, but I like how it looks
@@ -81,7 +84,7 @@ func part2(name string) (largestArea int) {
8184
8285 // Find the first valid
8386 for _ , r := range rectangles {
84- if isRectangleValid (r , boundaries ) {
87+ if isRectangleValid (r , bounds , minY ) {
8588 largestArea = r .Area
8689 break
8790 }
@@ -104,20 +107,22 @@ func createCoordinates(lines []string) (coords []grid.Point) {
104107}
105108
106109// This is slow because of, potentially, a lot of checks
107- func isRectangleValid (r Rectangle , boundaries map [ int ][ 2 ] int ) bool {
110+ func isRectangleValid (r Rectangle , boundaries [] Bounds , minY int ) bool {
108111 minX := min (r .P1 .X , r .P2 .X )
109112 maxX := max (r .P1 .X , r .P2 .X )
110- minY := min (r .P1 .Y , r .P2 .Y )
111- maxY := max (r .P1 .Y , r .P2 .Y )
113+ loY := min (r .P1 .Y , r .P2 .Y )
114+ hiY := max (r .P1 .Y , r .P2 .Y )
112115
113- for y := minY ; y <= maxY ; y ++ {
114- bounds , ok := boundaries [ y ]
116+ for y := loY ; y <= hiY ; y ++ {
117+ index := y - minY
115118
116- if ! ok {
119+ if index < 0 || index >= len ( boundaries ) {
117120 return false
118121 }
119122
120- if minX < bounds [0 ] || maxX > bounds [1 ] {
123+ b := boundaries [index ]
124+
125+ if ! b .Ok || minX < b .Min || maxX > b .Max {
121126 return false
122127 }
123128 }
@@ -130,53 +135,72 @@ func isRectangleValid(r Rectangle, boundaries map[int][2]int) bool {
130135// your list will always be on either the same row or the same column".
131136// So, we can find vertical and horizontal edges
132137
133- // row -> [min_x, max_x]
134- func createBoundaries (coords []grid.Point ) map [int ][2 ]int {
135- boundaries := map [int ][2 ]int {}
138+ type Bounds struct {
139+ Min , Max int
140+ Ok bool
141+ }
142+
143+ // First solution had a map of minX, maxX. But, this was slow when checking
144+ // for valid rectangles. This returns a slice and minY for faster lookup with y-minY.
145+ func createBoundariesSlice (coords []grid.Point ) ([]Bounds , int ) {
146+ if len (coords ) == 0 {
147+ return nil , 0
148+ }
149+
150+ // Find global Y-range
151+ minY := coords [0 ].Y
152+ maxY := coords [0 ].Y
153+
154+ for _ , c := range coords {
155+ minY = min (c .Y , minY )
156+ maxY = max (c .Y , maxY )
157+ }
136158
137- for i , c := range coords {
138- p1 := c
139- p2 := coords [(i + 1 )% len (coords )] // List wraps around
159+ // Allocate bounds
160+ size := maxY - minY + 1
161+ bounds := make ([]Bounds , size )
162+
163+ // Build similar to your map version
164+ for i := range coords {
165+ p1 := coords [i ]
166+ p2 := coords [(i + 1 )% len (coords )]
140167
141168 x1 , y1 := p1 .X , p1 .Y
142169 x2 , y2 := p2 .X , p2 .Y
143170
144171 if x1 == x2 {
145172 // Same x, create vertical edge from min y to max y
146- minY := min (y1 , y2 )
147- maxY := max (y1 , y2 ) + 1
148-
149- for y := minY ; y < maxY ; y ++ {
150- if _ , ok := boundaries [y ]; ! ok {
151- boundaries [y ] = [2 ]int {x1 , x1 }
152- } else {
153- cx1 := boundaries [y ][0 ]
154- cx2 := boundaries [y ][1 ]
173+ lo := min (y1 , y2 )
174+ hi := max (y1 , y2 )
155175
156- minX := min ( cx1 , x1 )
157- maxX := max ( cx2 , x1 )
176+ for y := lo ; y <= hi ; y ++ {
177+ idx := y - minY
158178
159- boundaries [y ] = [2 ]int {minX , maxX }
179+ if ! bounds [idx ].Ok {
180+ bounds [idx ] = Bounds {Min : x1 , Max : x1 , Ok : true }
181+ } else {
182+ b := bounds [idx ]
183+ b .Min = min (x1 , b .Min )
184+ b .Max = max (x1 , b .Max )
185+ bounds [idx ] = b
160186 }
161187 }
162188 } else if y1 == y2 {
163189 // same y, create horizontal edge from mix to max x
190+ row := y1 - minY
164191
165- if _ , ok := boundaries [ y1 ]; ! ok {
166- boundaries [ y1 ] = [ 2 ] int { min (x1 , x2 ), max (x1 , x2 )}
192+ if ! bounds [ row ]. Ok {
193+ bounds [ row ] = Bounds { Min : min (x1 , x2 ), Max : max (x1 , x2 ), Ok : true }
167194 } else {
168- cx1 := boundaries [y1 ][0 ]
169- cx2 := boundaries [y1 ][1 ]
170-
171- minX := min (min (cx1 , x1 ), x2 )
172- maxX := max (max (cx2 , x1 ), x2 )
173-
174- boundaries [y1 ] = [2 ]int {minX , maxX }
195+ b := bounds [row ]
196+ b .Min = min (min (x1 , x2 ), b .Min )
197+ b .Max = max (max (x1 , x2 ), b .Max )
198+ bounds [row ] = b
175199 }
176200 }
177201 }
178202
179- return boundaries
203+ return bounds , minY
180204}
181205
182206// math.Min / math.Max use float64s so these helpers
0 commit comments