Files
practice/pkg/questions/pacific_atlantic_water_flow/main.go
2026-03-06 19:17:30 -05:00

106 lines
2.1 KiB
Go

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
}