题目:
- 有一个
m × n
的矩形岛屿,与 太平洋 和 大西洋 相邻。 “太平洋” 处于大陆的左边界和上边界,而 “大西洋” 处于大陆的右边界和下边界。 - 这个岛被分割成一个由若干方形单元格组成的网格。给定一个
m x n
的整数矩阵heights
,heights[r][c]
表示坐标(r, c)
上单元格 高于海平面的高度 。 - 岛上雨水较多,如果相邻单元格的高度 小于或等于 当前单元格的高度,雨水可以直接向北、南、东、西流向相邻单元格。水可以从海洋附近的任何单元格流入海洋。
- 返回网格坐标
result
的 2D 列表 ,其中 r e s u l t [ i ] = [ r i , c i ] result[i] = [r_i, c_i] result[i]=[ri,ci] 表示雨水从单元格 ( r i , c i ) (r_i, c_i) (ri,ci) 流动 既可流向太平洋也可流向大西洋 。
示例:
- 输入: h e i g h t s = [ [ 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 ] ] heights = [[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]] heights=[[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 ] ] [[0,4],[1,3],[1,4],[2,2],[3,0],[3,1],[4,0]] [[0,4],[1,3],[1,4],[2,2],[3,0],[3,1],[4,0]]
解题思路:
题意其实是雨水从高往低流,给定的height
中的元素是否能满足 雨水同时能流向太平洋和大西洋,若可以的话,记录到结果集res
中。
一种简单的思路是:遍历height
数组中的每一个元素,标记其能流经的区域,然后判断能否同时流向太平洋和大西洋。
C++版整体代码(DFS)会超时版,需要优化:
class Solution {
public:
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
void dfs(vector<vector<int>>& heights, vector<vector<bool>>& visited, int x, int y){
if(visited[x][y]) return;
visited[x][y] = true;
for(int i = 0; i < 4; i++){
int nextx = x + dx[i], nexty = y + dy[i];
if(nextx < 0 || nextx >= heights.size() || nexty < 0 || nexty >= heights[0].size()) continue;
if(heights[x][y] < heights[nextx][nexty]) continue;
dfs(heights, visited, nextx, nexty);
}
return;
}
bool isResult(vector<vector<int>>& heights, int x, int y){
int n = heights.size(), m = heights[0].size();
vector<vector<bool>> visited = vector<vector<bool>>(n, vector<bool>(m, false));
dfs(heights, visited, x, y);
bool isPacific = false;
bool isAtlantic = false;
for(int i = 0; i < n; i++){
if(visited[i][0]){
isPacific = true;
break;
}
}
for(int i = 0; i < n; i++){
if(visited[i][m - 1]){
isAtlantic = true;
break;
}
}
for(int i = 0; i < m; i++){
if(visited[0][i]){
isPacific = true;
break;
}
}
for(int i = 0; i < m; i++){
if(visited[n - 1][i]){
isAtlantic = true;
break;
}
}
if(isPacific && isAtlantic) return true;
return false;
}
vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {
int n = heights.size(), m = heights[0].size();
vector<vector<int>> res;
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(isResult(heights, i, j)) res.push_back({i, j});
}
}
return res;
}
};
优化能通过版本:
从太平洋边上的节点逆流而上,将遍历过的节点都标记上。从大西洋的边上节点逆流而上,也将遍历过的节点都标记上。然后双方都标记过的节点就是既可以流向太平洋也可以流大西洋的节点。
C++版整体代码(DFS):
class Solution {
public:
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
void dfs(vector<vector<int>>& heights, vector<vector<bool>>& visited, int x, int y){
if(visited[x][y]) return;
visited[x][y] = true;
for(int i = 0; i < 4; i++){
int nextx = x + dx[i], nexty = y + dy[i];
if(nextx < 0 || nextx >= heights.size() || nexty < 0 || nexty >= heights[0].size()) continue;
if(heights[x][y] > heights[nextx][nexty]) continue;
dfs(heights, visited, nextx, nexty);
}
return;
}
vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {
int n = heights.size(), m = heights[0].size();
vector<vector<int>> res;
// 从太平洋边上出发的点,逆流可以遍历的点,做标记
vector<vector<bool>> pacific = vector<vector<bool>>(n, vector<bool>(m, false));
// 从大西洋边上出发的点,逆流可以遍历的点,做标记
vector<vector<bool>> atlantic = vector<vector<bool>>(n, vector<bool>(m, false));
// 上下侧节点遍历
for(int i = 0; i < n; i++){
dfs(heights, pacific, i, 0);
dfs(heights, atlantic, i, m - 1);
}
// 左右侧节点遍历
for(int i = 0; i < m; i++){
dfs(heights, pacific, 0, i);
dfs(heights, atlantic, n - 1, i);
}
// 全局遍历,当遇到太平洋与大西洋标记数组中都为true,也就是都遍历到的节点,即为结果节点
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(pacific[i][j] && atlantic[i][j]) res.push_back({i, j});
}
}
return res;
}
};