feat: friday
This commit is contained in:
105
pkg/pacific_atlantic_water_flow/main.go
Normal file
105
pkg/pacific_atlantic_water_flow/main.go
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
package pacificatlanticwaterflow
|
||||||
|
|
||||||
|
type Position struct{ X, Y int }
|
||||||
|
|
||||||
|
func (p Position) Neighbors() []Position {
|
||||||
|
return []Position{
|
||||||
|
{p.X + 1, p.Y},
|
||||||
|
{p.X - 1, p.Y},
|
||||||
|
{p.X, p.Y + 1},
|
||||||
|
{p.X, p.Y - 1},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Position) ToList() []int {
|
||||||
|
return []int{p.Y, p.X}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Board [][]int
|
||||||
|
|
||||||
|
func (b Board) Get(p Position) int {
|
||||||
|
if b.OutOfBounds(p) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
return b[p.Y][p.X]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Board) Height() int { return len(b) }
|
||||||
|
func (b Board) Width() int { return len(b[0]) }
|
||||||
|
|
||||||
|
func (b Board) OutOfBounds(p Position) bool {
|
||||||
|
return p.Y < 0 || p.Y >= b.Height() || p.X < 0 || p.X >= b.Width()
|
||||||
|
}
|
||||||
|
|
||||||
|
type Flow struct{ Pacific, Atlantic bool }
|
||||||
|
|
||||||
|
func (f *Flow) Merge(o Flow) {
|
||||||
|
f.Atlantic = f.Atlantic || o.Atlantic
|
||||||
|
f.Pacific = f.Pacific || o.Pacific
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Flow) Both() bool {
|
||||||
|
return f.Pacific && f.Atlantic
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Board) GetFlow(p Position) Flow {
|
||||||
|
return Flow{
|
||||||
|
Atlantic: p.Y >= b.Height() || p.X >= b.Width(),
|
||||||
|
Pacific: p.Y < 0 || p.X < 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func pacificAtlanticHelper(board Board, position Position, flows map[Position]Flow) Flow {
|
||||||
|
if flow, ok := flows[position]; ok {
|
||||||
|
return flow
|
||||||
|
}
|
||||||
|
|
||||||
|
if board.OutOfBounds(position) {
|
||||||
|
return board.GetFlow(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
flow := Flow{}
|
||||||
|
|
||||||
|
var top Position
|
||||||
|
plateau := map[Position]bool{}
|
||||||
|
unvisited := []Position{position}
|
||||||
|
for len(unvisited) > 0 {
|
||||||
|
top, unvisited = unvisited[len(unvisited)-1], unvisited[:len(unvisited)-1]
|
||||||
|
|
||||||
|
if board.Get(top) < board.Get(position) {
|
||||||
|
flow.Merge(pacificAtlanticHelper(board, top, flows))
|
||||||
|
} else if board.Get(top) == board.Get(position) {
|
||||||
|
if _, ok := plateau[top]; !ok {
|
||||||
|
plateau[top] = true
|
||||||
|
unvisited = append(unvisited, top.Neighbors()...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for mem := range plateau {
|
||||||
|
flows[mem] = flow
|
||||||
|
}
|
||||||
|
|
||||||
|
return flow
|
||||||
|
}
|
||||||
|
|
||||||
|
func PacificAtlantic(heights [][]int) [][]int {
|
||||||
|
flows := map[Position]Flow{}
|
||||||
|
board := Board(heights)
|
||||||
|
|
||||||
|
for y := range board.Height() {
|
||||||
|
for x := range board.Width() {
|
||||||
|
pacificAtlanticHelper(board, Position{x, y}, flows)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result := [][]int{}
|
||||||
|
for position, flow := range flows {
|
||||||
|
if flow.Both() {
|
||||||
|
result = append(result, position.ToList())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
62
pkg/pacific_atlantic_water_flow/main_test.go
Normal file
62
pkg/pacific_atlantic_water_flow/main_test.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package pacificatlanticwaterflow
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func sortResult(result [][]int) {
|
||||||
|
sort.Slice(result, func(i, j int) bool {
|
||||||
|
if result[i][0] != result[j][0] {
|
||||||
|
return result[i][0] < result[j][0]
|
||||||
|
}
|
||||||
|
return result[i][1] < result[j][1]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPacificAtlantic(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
heights [][]int
|
||||||
|
expected [][]int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "5x5 grid",
|
||||||
|
heights: [][]int{
|
||||||
|
{1, 2, 2, 3, 5},
|
||||||
|
{3, 2, 3, 4, 4},
|
||||||
|
{2, 4, 5, 3, 1},
|
||||||
|
{6, 7, 1, 4, 5},
|
||||||
|
{5, 1, 1, 2, 4},
|
||||||
|
},
|
||||||
|
expected: [][]int{{0, 4}, {1, 3}, {1, 4}, {2, 2}, {3, 0}, {3, 1}, {4, 0}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "3x2 all ones",
|
||||||
|
heights: [][]int{
|
||||||
|
{1, 1},
|
||||||
|
{1, 1},
|
||||||
|
{1, 1},
|
||||||
|
},
|
||||||
|
expected: [][]int{{0, 0}, {0, 1}, {1, 0}, {1, 1}, {2, 0}, {2, 1}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
result := PacificAtlantic(tc.heights)
|
||||||
|
sortResult(result)
|
||||||
|
sortResult(tc.expected)
|
||||||
|
|
||||||
|
if len(result) != len(tc.expected) {
|
||||||
|
t.Fatalf("expected %d results, got %d: %v", len(tc.expected), len(result), result)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range tc.expected {
|
||||||
|
if result[i][0] != tc.expected[i][0] || result[i][1] != tc.expected[i][1] {
|
||||||
|
t.Errorf("result[%d] = %v, expected %v", i, result[i], tc.expected[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user