给定一个 m x n 的非负整数矩阵来表示一片大陆上各个单元格的高度。“太平洋”处于大陆的左边界和上边界,而“大西洋”处于大陆的右边界和下边界。
规定水流只能按照上、下、左、右四个方向流动,且只能从高到低或者在同等高度上流动。
请找出那些水流既可以流动到“太平洋”,又能流动到“大西洋”的陆地单元的坐标。
提示:
输出坐标的顺序不重要
m 和 n 都小于150
示例:
给定下面的 5x5 矩阵:
太平洋 ^ ^ ^ ^ ^ ^ ^
^ 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 *
* * * * * 大西洋
返回:
[[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] (上图中带括号的单元).
逆流判断,即从边缘开始向里面推进,比如以上边界太平洋为例,首先上边界的每个元素能流入太平洋,大陆内能如果存在一个元素,该元素能流入上边界任意一个元素,则该元素也能通过上边界流入太平洋。
针对任意一个有效(能通过上边界流入太平洋的)元素,将其视为树的根节点,其上下左右方向的四个元素视为树的子节点,如果这四个元素中存在元素、其值大于根节点,则将其视为新的根节点,并可以作为基准开始新的递归搜索。
在该问题,可以进行
在DFS递归的过程中,如果上下左右邻近方向的元素已经被判断为有效元素,则直接跳过该元素(即:该元素已经在其余的位置被访问且满足条件,小心迷宫问题的循环圈)
关于该思路为什么叫做DFS,如果代码书写时,是按着根节点的左右上下的顺序来访问并判断子节点,则程序在执行时,会先沿着某一有效方向,层层递归、直到访问到最深层、最后一个满足要求的节点,然后最深层、最后一个满足要求的节点会先完整地被判断其上下左右四个方向,然后再回溯,再倒数第二执行剩余方向的判断……,回溯……
def pacificAtlantic(self, matrix):
if not any(matrix): return []
# 流向太平洋的位置
res1 = set()
# 流向大西洋的位置
res2 = set()
row = len(matrix)
col = len(matrix[0])
# 从边界遍历
def dfs(i, j, cur, res):
res.add((i, j))
for x, y in [[1, 0], [-1, 0], [0, 1], [0, -1]]:
tmp_i = i + x
tmp_j = j + y
if 0 <= tmp_i < row and 0 <= tmp_j < col and matrix[i][j] <= matrix[tmp_i][tmp_j] and (tmp_i, tmp_j) not in res:
dfs(tmp_i, tmp_j, matrix[i][j], res)
# 太平洋
for i in range(row):
dfs(i, 0, 0, res1)
# 太平洋
for j in range(col):
dfs(0, j, 0, res1)
# 大西洋
for i in range(row):
dfs(i, col - 1, 0, res2)
# 大西洋
for j in range(col):
dfs(row - 1, j, 0, res2)
return res1 & res2
从边缘往里推进,逆流,相比于DFS而言,BFS采用栈,先将太平洋对应的两条边缘的元素进行标记并均放入栈中,逐一取出栈中的元素,判断能流入该元素(该元素左右上下邻近方向的元素中比该元素大、且还未被标记)的压入栈,依次循环执行弹出、判断、压入栈,直到栈内元素为空。
该方法相比于DFS,遍历的层级是按着层级来展开的,即优先把同一层的每个根节点的四个方向先遍历,然后处理,处理之后压入栈,待上一层所有节点被遍历处理完之后,栈首的元素变为下一层所有的节点的第一个节点。
def pacificAtlantic(self, matrix: List[List[int]]) -> List[List[int]]:
if not any(matrix): return []
m, n = len(matrix), len(matrix[0])
def bfs(q):
res_set = set()
while q:
x, y = q.pop()
res_set.add((x, y))
for i, j in [(x+1, y), (x-1, y), (x, y-1), (x, y+1)]:
if 0 <= i < m and 0 <= j < n and matrix[x][y] <= matrix[i][j] and (i, j) not in res_set:
q.append((i, j))
return res_set
##list的合并直接使用+
pacificq = [(0, j) for j in range(n)] + [(i, 0) for i in range(m)] #太平洋
atlanticq = [(m-1, j) for j in range(n)] + [(i, n-1) for i in range(m)]
return list(bfs(pacificq) & bfs(atlanticq))#交集