|
| 1 | +# 毎日一题 - 417. 太平洋大西洋水流问题 |
| 2 | + |
| 3 | +## 信息卡片 |
| 4 | + |
| 5 | +* 时间:2019-08-13 |
| 6 | +* 题目链接:https://leetcode-cn.com/problems/pacific-atlantic-water-flow |
| 7 | +- tag:`Backtracking` `DFS` |
| 8 | +## 题目描述 |
| 9 | + |
| 10 | +给定一个 m x n 的非负整数矩阵来表示一片大陆上各个单元格的高度。“太平洋”处于大陆的左边界和上边界,而“大西洋”处于大陆的右边界和下边界。 |
| 11 | + |
| 12 | +规定水流只能按照上、下、左、右四个方向流动,且只能从高到低或者在同等高度上流动。 |
| 13 | + |
| 14 | +请找出那些水流既可以流动到“太平洋”,又能流动到“大西洋”的陆地单元的坐标。 |
| 15 | + |
| 16 | +提示: |
| 17 | + |
| 18 | +输出坐标的顺序不重要 |
| 19 | +m 和 n 都小于150 |
| 20 | + |
| 21 | +示例: |
| 22 | + |
| 23 | +``` |
| 24 | +给定下面的 5x5 矩阵: |
| 25 | +
|
| 26 | + 太平洋 ~ ~ ~ ~ ~ |
| 27 | + ~ 1 2 2 3 (5) * |
| 28 | + ~ 3 2 3 (4) (4) * |
| 29 | + ~ 2 4 (5) 3 1 * |
| 30 | + ~ (6) (7) 1 4 5 * |
| 31 | + ~ (5) 1 1 2 4 * |
| 32 | + * * * * * 大西洋 |
| 33 | +
|
| 34 | +返回: |
| 35 | +
|
| 36 | +[[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] (上图中带括号的单元). |
| 37 | +``` |
| 38 | + |
| 39 | + |
| 40 | + |
| 41 | +## 参考答案 |
| 42 | + |
| 43 | +- 方法1:直接采用回溯法 超时 |
| 44 | + |
| 45 | +直接判断 水流既可以流动到“太平洋”,又能流动到“大西洋”的陆地单元的坐标 |
| 46 | +采用方法是 |
| 47 | +回溯法(英语:backtracking)是暴力搜索法中的一种。 |
| 48 | +在最坏的情况下,回溯法会导致一次复杂度为指数时间的计算。 |
| 49 | +在这个题目中,这个题目中正好就是如此。 |
| 50 | +因为需要等到上下左右全部计算完毕才有确定答案。 |
| 51 | + |
| 52 | +m 和 n =150,肯定超时。 |
| 53 | + |
| 54 | +- 方法2:动态规划+回溯法 |
| 55 | + |
| 56 | +思路: |
| 57 | + |
| 58 | +总体思路还是回溯,我们对能够流入太平洋的(第一行和第一列)开始进行上下左右探测。 |
| 59 | + |
| 60 | +同样我们对能够流入大西洋的(最后一行和最后一列)开始进行上下左右探测。 |
| 61 | + |
| 62 | +最后将探测结果进行合并即可。合并的条件就是当前单元既能流入太平洋又能流入大西洋。 |
| 63 | + |
| 64 | + |
| 65 | +扩展: |
| 66 | + |
| 67 | +如果题目改为能够流入大西洋或者太平洋,我们只需要最后合并的时候,条件改为求或即可 |
| 68 | + |
| 69 | +## 参考代码 |
| 70 | + |
| 71 | +- JavaScript Code |
| 72 | + |
| 73 | +```js |
| 74 | +function dfs(i, j, height, m, matrix, rows, cols) { |
| 75 | + if (i >= rows || i < 0) return; |
| 76 | + if (j >= cols || j < 0) return; |
| 77 | + |
| 78 | + if (matrix[i][j] < height) return; |
| 79 | + |
| 80 | + if (m[i][j] === true) return; |
| 81 | + |
| 82 | + m[i][j] = true; |
| 83 | + |
| 84 | + dfs(i + 1, j, matrix[i][j], m, matrix, rows, cols); |
| 85 | + dfs(i - 1, j, matrix[i][j], m, matrix, rows, cols); |
| 86 | + dfs(i, j + 1, matrix[i][j], m, matrix, rows, cols); |
| 87 | + dfs(i, j - 1, matrix[i][j], m, matrix, rows, cols); |
| 88 | +} |
| 89 | +/** |
| 90 | + * @param {number[][]} matrix |
| 91 | + * @return {number[][]} |
| 92 | + */ |
| 93 | +var pacificAtlantic = function(matrix) { |
| 94 | + const rows = matrix.length; |
| 95 | + if (rows === 0) return []; |
| 96 | + const cols = matrix[0].length; |
| 97 | + const pacific = Array.from({ |
| 98 | + length: rows |
| 99 | + }, |
| 100 | + () = >Array(cols).fill(false)); |
| 101 | + const atlantic = Array.from({ |
| 102 | + length: rows |
| 103 | + }, |
| 104 | + () = >Array(cols).fill(false)); |
| 105 | + const res = []; |
| 106 | + |
| 107 | + for (let i = 0; i < rows; i++) { |
| 108 | + dfs(i, 0, 0, pacific, matrix, rows, cols); |
| 109 | + dfs(i, cols - 1, 0, atlantic, matrix, rows, cols); |
| 110 | + } |
| 111 | + |
| 112 | + for (let i = 0; i < cols; i++) { |
| 113 | + dfs(0, i, 0, pacific, matrix, rows, cols); |
| 114 | + dfs(rows - 1, i, 0, atlantic, matrix, rows, cols); |
| 115 | + } |
| 116 | + |
| 117 | + for (let i = 0; i < rows; i++) { |
| 118 | + for (let j = 0; j < cols; j++) { |
| 119 | + if (pacific[i][j] === true && atlantic[i][j] === true) res.push([i, j]); |
| 120 | + } |
| 121 | + } |
| 122 | + |
| 123 | + return res; |
| 124 | +}; |
| 125 | +``` |
| 126 | + |
| 127 | + |
| 128 | +- C++ Code |
| 129 | + |
| 130 | + ```c++ |
| 131 | + class Solution { |
| 132 | + public: |
| 133 | + vector<vector<int> > pacificAtlantic( vector<vector<int> > & matrix ) |
| 134 | + { |
| 135 | + vector<vector<int> > out; |
| 136 | + int row = matrix.size(); |
| 137 | + if ( 0 == row ) |
| 138 | + return(out); |
| 139 | + int col = matrix[0].size(); |
| 140 | + if ( 0 == col ) |
| 141 | + return(out); |
| 142 | + |
| 143 | + /* 能流动到“太平洋"的陆地 */ |
| 144 | + vector<vector<bool> > dp1( row, vector<bool>( col, false ) ); |
| 145 | + /* 能流动到“大西洋"的陆地 */ |
| 146 | + vector<vector<bool> > dp2( row, vector<bool>( col, false ) ); |
| 147 | + |
| 148 | + /* 从第一行/最后一行出发寻找连同节点,不变的x坐标 */ |
| 149 | + for ( int j = 0; j < col; j++ ) |
| 150 | + { |
| 151 | + dfs( 0, j, INT_MIN, matrix, dp1 ); |
| 152 | + dfs( row - 1, j, INT_MIN, matrix, dp2 ); |
| 153 | + } |
| 154 | + /* 从第一列/最后一列出发寻找连同节点,不变的y坐标 */ |
| 155 | + for ( int i = 0; i < row; i++ ) |
| 156 | + { |
| 157 | + dfs( i, 0, INT_MIN, matrix, dp1 ); |
| 158 | + dfs( i, col - 1, INT_MIN, matrix, dp2 ); |
| 159 | + } |
| 160 | + |
| 161 | + vector<int> temp( 2 ); |
| 162 | + for ( int i = 0; i < row; i++ ) |
| 163 | + { |
| 164 | + for ( int j = 0; j < col; j++ ) |
| 165 | + { |
| 166 | + /* 请找出那些水流既可以流动到“太平洋”,又能流动到“大西洋”的陆地单元的坐标。 */ |
| 167 | + if ( dp1[i][j] == true && dp2[i][j] == true ) |
| 168 | + { |
| 169 | + temp[0] = i; |
| 170 | + temp[1] = j; |
| 171 | + out.push_back( temp ); |
| 172 | + } |
| 173 | + } |
| 174 | + } |
| 175 | + return(out); |
| 176 | + } |
| 177 | + |
| 178 | + |
| 179 | + void dfs( int row, int col, int height, |
| 180 | + vector<vector<int> > & matrix, vector<vector<bool> > & visited ) |
| 181 | + { |
| 182 | + if ( row < 0 || row >= matrix.size() || |
| 183 | + col < 0 || col >= matrix[0].size() |
| 184 | + ) |
| 185 | + { |
| 186 | + return; |
| 187 | + } |
| 188 | + |
| 189 | + if ( visited[row][col] == true ) |
| 190 | + { |
| 191 | + return; |
| 192 | + } |
| 193 | + |
| 194 | + if ( height > matrix[row][col] ) |
| 195 | + { |
| 196 | + return; |
| 197 | + } |
| 198 | + |
| 199 | + visited[row][col] = true; |
| 200 | + |
| 201 | + dfs( row + 1, col, matrix[row][col], matrix, visited ); |
| 202 | + dfs( row - 1, col, matrix[row][col], matrix, visited ); |
| 203 | + dfs( row, col + 1, matrix[row][col], matrix, visited ); |
| 204 | + dfs( row, col - 1, matrix[row][col], matrix, visited ); |
| 205 | + } |
| 206 | + }; |
| 207 | + ``` |
| 208 | +
|
| 209 | + |
| 210 | +
|
| 211 | +
|
| 212 | +
|
| 213 | +## 其他优秀解答 |
| 214 | +
|
| 215 | +> ##### 暂缺 |
0 commit comments