▶ 给定方阵 grid,其元素的值为 D0n-1,代表网格中该点处的高度。现在网格中开始积水,时刻 t 的时候所有值不大于 t 的格点被水淹没,当两个相邻格点(上下左右四个方向)的值都不超过 t 的时候我们称他们连通,即可以通过游泳到达,请问能将主对角两顶点((0, 0) 和 (n-1, n-1))连通的最小时刻是多少?例如 下图的最小连通时间为 16 。
● 自己的代码,22 ms,简单 BFS,普通队列
1 class Solution 2 { 3 public: 4 int swimInWater(vector<vector<int>>& grid)//set a binary search to find a proper moment 5 { 6 const int n = grid.size(); 7 int lp, rp, mp; 8 for (lp = max(2 * n - 2, max(grid[0][0], grid[n - 1][n - 1])) - 1, rp = n * n, mp = (lp + rp) / 2; lp < rp && mp > lp; mp = (lp + rp) / 2) 9 { // 时间最小是 2n-2,最大是 n^2-1 10 if (swim(grid, mp)) 11 rp = mp; 12 else 13 lp = mp; 14 } 15 return rp; 16 } 17 bool swim(vector<vector<int>>& grid, int time)// swimming at the moment 'time', can I reach the point (n-1, n-1)? 18 { 19 const int n = grid.size(); 20 vector<vector<bool>> table(n, vector<bool>(n, false)); 21 queue<vector<int>> qq; 22 vector<int> temp; 23 int row, col; 24 for (qq.push({ 0, 0 }), table[0][0] = true; !qq.empty();) 25 { 26 temp = qq.front(), qq.pop(), row = temp[0], col = temp[1]; 27 if (row == n - 1 && col == n - 1) 28 return true; 29 30 if (row > 0 && grid[row - 1][col] <= time && !table[row - 1][col])// up 31 qq.push({ row - 1, col }), table[row - 1][col] = true; 32 if (col > 0 && grid[row][col - 1] <= time && !table[row][col - 1])// left 33 qq.push({ row, col - 1 }), table[row][col - 1] = true; 34 if (row < n - 1 && grid[row + 1][col] <= time && !table[row + 1][col])// down 35 qq.push({ row + 1, col }), table[row + 1][col] = true; 36 if (col < n - 1 && grid[row][col + 1] <= time && !table[row][col + 1])// right 37 qq.push({ row, col + 1 }), table[row][col + 1] = true; 38 } 39 return false; 40 } 41 };
● 大佬的代码,13 ms,DFS,注意这里使用了一个数组 dir 来决定搜索方向,比较有趣的用法
1 class Solution 2 { 3 public: 4 int swimInWater(vector<vector<int>>& grid) 5 { 6 const int n = grid.size(); 7 int lp, rp, mp; 8 for (lp = grid[0][0], rp = n * n - 1; lp < rp;) 9 { 10 mp = lp + (rp - lp) / 2; 11 if (valid(grid, mp)) 12 rp = mp; 13 else 14 lp = mp + 1; 15 } 16 return lp; 17 } 18 bool valid(vector<vector<int>>& grid, int waterHeight) 19 { 20 const int n = grid.size(); 21 const vector<int> dir({ -1, 0, 1, 0, -1 }); 22 vector<vector<bool>> visited(n, vector<bool>(n, 0)); 23 return dfs(grid, visited, dir, waterHeight, 0, 0, n); 24 } 25 bool dfs(vector<vector<int>>& grid, vector<vector<bool>>& visited, vector<int>& dir, int waterHeight, int row, int col, int n) 26 { 27 int i, r, c; 28 visited[row][col] = true; 29 for (i = 0; i < 4; ++i) 30 { 31 r = row + dir[i], c = col + dir[i + 1]; 32 if (r >= 0 && r < n && c >= 0 && c < n && visited[r][c] == false && grid[r][c] <= waterHeight) 33 { 34 if (r == n - 1 && c == n - 1) 35 return true; 36 if (dfs(grid, visited, dir, waterHeight, r, c, n)) 37 return true; 38 } 39 } 40 return false; 41 } 42 };
● 大佬的代码,185 ms,DP + DFS,维护一个方阵 dp,理解为“沿着当前搜索路径能够到达某一格点的最小时刻”,初始假设 dp = [INT_MAX] ,即所有的格点都要在 INT_MAX 的时刻才能到达,深度优先遍历每个点,不断下降每个点的值(用该点原值和用于遍历的临时深度值作比较,两者都更新为他们的较小者)
1 class Solution 2 { 3 public: 4 int swimInWater(vector<vector<int>> &grid) 5 { 6 const int m = grid.size(); 7 vector<vector<int>> dp(m, vector<int>(m, INT_MAX)); 8 helper(grid, 0, 0, 0, dp); 9 return dp[m - 1][m - 1]; 10 } 11 void helper(vector<vector<int>> &grid, int row, int col, int deep, vector<vector<int>> &dp) 12 { 13 const int m = grid.size(); 14 int i, x, y; 15 deep = max(deep, grid[row][col]); 16 if (dp[row][col] <= deep) 17 return; 18 for (dp[row][col] = deep, i = 0; i < direction.size(); i++) 19 { 20 x = row + direction[i][0], y = col + direction[i][1]; 21 if (x >= 0 && x < m && y >= 0 && y < m) 22 helper(grid, x, y, dp[row][col], dp); 23 } 24 } 25 vector<vector<int>> direction = { { -1, 0 },{ 1, 0 },{ 0, 1 },{ 0, -1 } }; 26 };
● 大佬的代码,18 ms,DFS,优先队列,Dijkstra算法,相当于在搜索队列中,总是优先研究最小时刻的点
1 class Solution 2 { 3 public: 4 int swimInWater(vector<vector<int>>& grid) 5 { 6 const int n = grid.size(); 7 const vector<int> dir({ -1, 0, 1, 0, -1 }); 8 int ans, i, r, c; 9 priority_queue<vector<int>, vector<vector<int>>, greater<vector<int>>> pq; 10 vector<vector<bool>> visited(n, vector<bool>(n, false)); 11 vector<int> cur; 12 for (visited[0][0] = true, ans = max(grid[0][0], grid[n - 1][n - 1]), pq.push({ ans, 0, 0 }); !pq.empty();) 13 { 14 cur = pq.top(),pq.pop(), ans = max(ans, cur[0]); 15 for (i = 0; i < 4; i++) 16 { 17 r = cur[1] + dir[i], c = cur[2] + dir[i + 1]; 18 if (r >= 0 && r < n && c >= 0 && c < n && visited[r][c] == false) 19 { 20 visited[r][c] = true; 21 if (r == n - 1 && c == n - 1) 22 return ans; 23 pq.push({ grid[r][c], r, c }); 24 } 25 } 26 } 27 return -1; 28 } 29 };
● 大佬的代码,11 ms,使用那个 DP + DFS 解法的深度更新思路,把搜索方式换成 BFS
1 class Solution 2 { 3 public: 4 int swimInWater(vector<vector<int>>& grid) 5 { 6 const int n = grid.size(); 7 const vector<int> dir({ -1, 0, 1, 0, -1 }); 8 int ans, i, r, c; 9 vector<vector<bool>> visited(n, vector<bool>(n, false)); 10 priority_queue<vector<int>, vector<vector<int>>, greater<vector<int>>> pq; 11 vector<int> cur; 12 queue<pair<int, int>> myq; 13 pair<int, int> p; 14 for (visited[0][0] = true, ans = max(grid[0][0], grid[n - 1][n - 1]), pq.push({ ans, 0, 0 }); !pq.empty();) 15 { 16 cur = pq.top(), pq.pop(), ans = max(ans, cur[0]); 17 for (myq.push({ cur[1], cur[2] }); !myq.empty();) 18 { 19 p = myq.front(), myq.pop(); 20 if (p.first == n - 1 && p.second == n - 1) 21 return ans; 22 for (i = 0; i < 4; ++i) 23 { 24 r = p.first + dir[i], c = p.second + dir[i + 1]; 25 if (r >= 0 && r < n && c >= 0 && c < n && visited[r][c] == 0) 26 { 27 visited[r][c] = true; 28 if (grid[r][c] <= ans) 29 myq.push({ r, c }); 30 else 31 pq.push({ grid[r][c], r, c }); 32 } 33 } 34 } 35 } 36 return -1; 37 } 38 };
▶ 附上一个测试数据,答案为 266
1 { 2 {105, 209, 171, 91, 64, 394, 279, 11, 45, 84, 207, 321, 216, 197, 381, 377, 78, 19, 203, 198}, 3 { 141, 10, 335, 170, 265, 104, 338, 40, 397, 376, 346, 356, 212, 154, 280, 177, 247, 90, 87, 360 }, 4 { 99, 59, 242, 149, 344, 172, 276, 230, 133, 193, 284, 345, 46, 363, 30, 142, 295, 70, 224, 200 }, 5 { 251, 88, 379, 72, 319, 272, 243, 165, 180, 182, 387, 264, 23, 67, 137, 342, 125, 139, 144, 367 }, 6 { 94, 211, 151, 37, 290, 112, 343, 157, 300, 271, 260, 373, 369, 294, 289, 57, 44, 12, 20, 340 }, 7 { 220, 368, 186, 277, 181, 187, 273, 214, 315, 337, 328, 18, 231, 223, 331, 75, 275, 96, 135, 150 }, 8 { 202, 74, 27, 184, 399, 341, 49, 62, 261, 86, 314, 383, 302, 257, 61, 148, 268, 120, 36, 25 }, 9 { 15, 253, 285, 185, 226, 146, 126, 122, 83, 361, 110, 234, 183, 239, 52, 190, 152, 81, 136, 188 }, 10 { 39, 199, 358, 26, 301, 116, 32, 386, 29, 138, 393, 159, 102, 140, 370, 227, 282, 111, 5, 33 }, 11 { 189, 35, 132, 54, 210, 235, 28, 353, 281, 127, 318, 58, 100, 286, 384, 24, 307, 252, 80, 103 }, 12 { 244, 176, 124, 79, 161, 355, 218, 398, 392, 380, 225, 121, 178, 352, 329, 322, 167, 51, 313, 85 }, 13 { 107, 118, 351, 287, 324, 283, 48, 320, 82, 364, 357, 16, 219, 330, 89, 143, 241, 262, 71, 191 }, 14 { 95, 97, 3,7, 270, 249, 213, 339, 362, 298, 4, 258, 248, 390, 299, 306, 156, 164, 109, 229 }, 15 { 221, 9, 228, 160, 274, 263, 374, 147, 98, 63, 13, 41, 326, 396, 349, 372, 385, 317, 325, 266 }, 16 { 53, 131, 173, 312, 174, 114, 250, 119, 163, 22, 246, 92, 278, 365, 292, 215, 14, 304, 204, 73 }, 17 { 233, 323, 366, 130, 378, 305, 311, 93, 134, 217, 297, 327, 232, 194, 240, 1, 208, 6, 310, 47 }, 18 { 69, 101, 332, 195, 254, 236, 50, 166, 56, 168, 267, 17, 359, 347, 65, 316, 238, 296, 348, 222 }, 19 { 76, 123, 129, 293, 391, 2, 245, 108, 303, 38, 66, 55, 43, 256, 162, 60, 179, 77, 336, 21 }, 20 { 196, 388, 333, 395, 42, 382, 291, 237, 288, 375, 128, 145, 192, 158, 350, 259, 206, 34, 334, 255 }, 21 { 201, 175, 153, 68, 205, 155, 115, 269, 389, 169, 371, 308, 117, 31, 354, 8, 113, 309, 106, 0 } 22 };