2020/3/27 打卡
题目
给定一个 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]] (上图中带括号的单元).
解释: 为什么这几个点 可以流到两个海洋中, 是因为比如(3,1)这个位置,其海拔高,因此 是可以自由的流向所有海拔低的位置,因此肯定满足。
同理(1,3)位置既能流向低海拔的上面,也能流向同等海拔的右边。
思路
这种流向判别问题,其实最简单的思路就是DFS,而且可以使用双重DFS的思路,对每个位置点启动DFS上的判别,这是最简单的思路。
但是时间复杂度高。
改进下,使用有剪枝的DFS方式,从边界往内流来启动DFS,只在 海洋边界上进行DFS操作,且使用 q_flag 和 a_flag 两个标记标识 不同海洋的可流向性。
代码
# 时间复杂度为O(M*N) 空间复杂度为O(M*N)
class Solution:
def pacificAtlantic(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: List[List[int]]
"""
if not matrix:
return []
# 设定行走的四个方向。
step = [[-1, 0], [1, 0], [0, -1], [0, 1]]
res = []
row = len(matrix)
col = len(matrix[0])
# 这里分别 标记能流向大西洋 和 太平洋的可行性,flag为1表示能流过去。 这个是重点,之后会针对每个位置点都计算出两个标记来。
q_flag = [[False] * col for _ in range(row)]
a_flag = [[False] * col for _ in range(row)]
# 接下来是dfs,从海洋边界开始往内去 获取每个位置点的两种可流到性, 目标就是获取实际的 q_flag 和 a_flag标记。
def dfs(i, j, visited):
visited[i][j] = True
for x, y in step:
# 先尝试性的移动。
tmp_i, tmp_j = i + x, j + y
# 如果 可以继续往内延伸时,进行延伸是不满足流向条件时(不能往高处流,判别过的不再判别。),就结束掉,否则继续往内延伸,
if tmp_i < 0 or tmp_j < 0 or tmp_i >= row or tmp_j >= col or matrix[tmp_i][tmp_j] < matrix[i][j] or visited[tmp_i][tmp_j]:
continue
dfs(tmp_i, tmp_j, visited)
# 这里注意一定是从 从两个海洋边界向陆地搜索,否则会超时 。 进行边界往内的搜索,并完成对内陆结点流向可能性,使用延伸的方法做标记。
for m in range(row):
# 分别做 大西洋和太平洋 流向可达性的判别。 分别尝试往内流的延伸情况,注意 对于标记的获取 是分别的,两个河流分别判别。
dfs(m, 0, q_flag)
dfs(m, col - 1, a_flag)
for n in range(col):
dfs(0, n, q_flag)
dfs(row - 1, n, a_flag)
# 最后 是流向上的判别。
for i in range(row):
for j in range(col):
# 简单的判别两个海洋都能流到的,就是成功的目标位置。
if q_flag[i][j] and a_flag[i][j]:
res.append([i, j])
return res