Pacific Atlantic Water Flow
m x n
크기의 사각형 모양의 섬 정보가 주어진다. 섬은 태평양(Pacific
Ocean)과 대서양(Atlantic Ocean) 모두에 둘러쌓여 있다. 태평양은 왼쪽과
위쪽에, 대서양은 오른쪽과 아래쪽에 있다.
섬 정보는 heights
배열로 주어지는데 heights[row][col]
은 섬의
(row, col)
위치에서의 땅의 높이를 나타낸다.
섬에는 비가 엄청나게 많이 오는데, 비는 현재 땅의 동서남북으로 인접한 땅 중에서 높이가 같거나 더 작은 곳으로 흘러내린다. 최종적으로 비는 태평양과 대서양으로 흘러간다.
이때, 비가 양쪽 바다 모두로 흘러갈 수 있는 땅의 좌표의 리스트를 구하자.
\(1 \leq m, n \leq 200\) 이고 높이는 \(0 \sim 10^5\) 이다.
예를 들어 아래 땅을 보자.
그림에서 노랗게 칠해진 땅은 비가 양 쪽 바다 모두로 흘러갈 수 있다. 따라서 답은 이 땅들의 좌표 목록이다.
그래프 탐색
이거 꽤나 신박한 그래프 탐색 문제라서 재밌게 풀었다.
일단 언뜻 생각하기에 가장 높은 곳을 찾아서 어찌 해야할 것 같지만, 잘 생각해보면 가장 높은 곳이 아니라 인접한 땅을 기준으로 가장 높은 곳을 찾아야 한다. 그런데 이렇게 찾을려면 전체 배열을 뒤지면서 각 땅마다 네 방향을 다 봐야한다. 거기다 이 높은 지점들을 찾더라도 이 지점들 중에서 양쪽 바다로 모두 흘러갈 수 있는 곳을 또 찾아야 한다. 즉, 문제의 조건을 그대로 시뮬레이션 하기에는 꽤 복잡하다.
그래서 약간 발상의 전환이 필요한데, 문제를 듀얼로 생각해보는 것이다. 그러니까 비가 흘러서 내려가는게 아니라, 거꾸로 바다에서 물이 땅을 따라 올라간다고 생각해보자. 즉 바다와 인접한 모든 땅에서 출발해서, 네 방향 중 더 높거나 같은 높이의 땅으로 타고 올라가면서 땅을 적신다고 해보자. 그러면 태평양이 적실 수 있는 땅과 대서양이 적실 수 있는 땅의 집합이 나오는데, 이 두 집합의 교집합이 결국 우리가 원하는 답이 됨을 알 수 있다.
바다가 적실 땅을 알아보려면 결국 그래프 탐색이 필요하다. 여기서는 BFS로 탐색하자. 그러면 BFS의 입력으로 탐색에 쓰일 큐를 직접 받는 게 좋아보인다. 왜냐하면 태평양과 대서양의 출발 지점이 각각 다르기 때문이다. 그걸 제외하면 탐색 알고리즘은 동일하다. 탐색 결과로는 방문한 모든 땅의 집합을 리턴하면 된다. 그래야 최종적으로 두 바다에서 모두에서 방문 가능한 땅의 위치를 알 수 있다.
from collections import deque
def pacificAtlantic(heights):
m, n = len(heights), len(heights[0])
def bfs(queue):
lands = set()
acc = [(1, 0), (0, 1), (-1, 0), (0, -1)]
while queue:
cur = queue.popleft()
lands.add(cur)
for dx, dy in acc:
cand = (cur[0] + dx, cur[1] + dy)
if cand[0] < 0 or cand[1] < 0 or cand[0] >= m or cand[1] >= n:
continue
if cand in lands:
continue
if heights[cand[0]][cand[1]] >= heights[cur[0]][cur[1]]:
queue.append(cand)
return lands
pacific, atlantic = deque(), deque()
for c in range(n):
pacific.append((0, c))
atlantic.append((m - 1, c))
for r in range(m):
pacific.append((r, 0))
atlantic.append((r, n - 1))
return bfs(pacific) & bfs(atlantic)