解法一:题目可以理解为从(0,0)到(n-1,n-1)的所有路径的最大海拔的最小值,max(路径最大海拔)。那么对于每一个点,求从(0 , 0)到该点的所有路径的最大值的最小值。可以用bfs来做,用maxele存储从(0,0)到该点的路径中的最大值的最小值,用inque防止cell在队列中重复存在;
class Solution { public: int swimInWater(vector<vector<int>>& grid) { int n = grid.size() ; vector<vector<int>> inque(n , vector<int>(n , 0)) , maxele(n , vector<int>(n , INT_MAX)) ; queue<int> q ; q.push(0) ; inque[0][0] = 1 ; maxele[0][0] = grid[0][0] ; while(!q.empty()) { int i = q.front() / n , j = q.front() % n ; q.pop() ; inque[i][j] = 0 ; for(int k = 0 ; k < 4 ; k++) { int ni = i + dir[k] , nj = j + dir[k+1] ; if(ni < 0 || ni >= n || nj < 0 || nj >= n) continue; if(max(maxele[i][j] , grid[ni][nj]) < maxele[ni][nj]) { maxele[ni][nj] = max(maxele[i][j] , grid[ni][nj]) ; if(!inque[ni][nj]) { q.push(ni * n + nj) ; inque[ni][nj] = 1 ; } } } } return maxele[n-1][n-1]; } private: vector<int> dir = {-1, 0 , 1, 0 , -1}; };
解法二:
cell中的海拔是[0 , N*N - 1]的排列,所以所求的least time一定处于[0 , N*N-1]的范围内,可以使用二分搜索;给定x,如果找到一条路径,路径中的每一个cell的海拔都小于或等于x,则r = x ;否则l = x + 1 ;(路径搜索可以用dfs或者bfs)
dfs(使用dfs一定要记得写上递归基)(时间复杂度(O(N^2log(N^2))) , 8ms.因为只搜索一条可行路径,不需要遍历所有路径,相较bfs更快)
class Solution { public: int swimInWater(vector<vector<int>>& grid) { int n = grid.size() ; int l = grid[0][0] , r = n * n - 1 ; while(l < r) { int mid = l + (r - l) / 2; if(valid(mid , grid)) r = mid ; else l = mid + 1 ; } return l ; } private: vector<int> dir = {-1 , 0 , 1 , 0 , -1}; bool valid(int x , vector<vector<int>>& grid) { int n = grid.size() ; vector<vector<int>> visited(n , vector<int>(n , 0)); return dfs(0 , 0 , x , visited , grid) ; } bool dfs(int r , int c , int x , vector<vector<int>>& visited , vector<vector<int>> &grid) { int n = grid.size() ; if(r == n - 1 && c == n - 1) return true ; visited[r][c] = 1 ; for(int k = 0 ; k < 4 ; k++) { int nr = r + dir[k] , nc = c + dir[k+1] ; if(nr < 0 || nr >= n || nc < 0 || nc >= n || visited[nr][nc] || grid[nr][nc] > x) continue ; if(dfs(nr , nc , x , visited , grid)) return true; } return false; } };
bfs(28ms)
class Solution { public: int swimInWater(vector<vector<int>>& grid) { int n = grid.size() ; int l = grid[0][0] , r = n * n - 1 ; while(l < r) { int mid = l + (r - l) / 2; if(bfs(mid , grid)) r = mid ; else l = mid + 1 ; } return l ; } private: vector<int> dir = {-1 , 0 , 1 , 0 , -1}; bool bfs(int x , vector<vector<int>>& grid) { int n = grid.size() ; vector<vector<int>> visited(n , vector<int>(n , 0)); queue<int> q ; q.push(0) ; visited[0][0] = 1 ; while(!q.empty()) { int r = q.front() / n , c = q.front() % n ; q.pop() ; if(r == n - 1 && c == n - 1) return true ; for(int k = 0 ; k < 4 ; k++) { int nr = r + dir[k] , nc = c + dir[k + 1]; if(nr < 0 || nr >= n || nc < 0 || nc >= n || visited[nr][nc] || grid[nr][nc] > x) continue ; visited[nr][nc] = 1 ; q.push(nr * n + nc) ; } } return false; } };
解法三:在搜索路径的过程中,我们优先选择目前为止搜索到的海拔最小的cell继续搜索,因为每个cell可以往四个方向搜索,所以任意两个cell都连通。所以可以用贪心的方法做, 如果不是任意两个cell都连通,就不能用贪心来做;
priority_queue , 在用priority_queue或者queue或者deque或stack的时候,记得要pop;(32ms)
class Solution { public: int swimInWater(vector<vector<int>>& grid) { int res = grid[0][0] , n = grid.size(); priority_queue<pair<int,int> , vector<pair<int,int>> , greater<pair<int,int>> > q ; vector<vector<int>> vis(n , vector<int>(n , 0)) ; vector<int> dir = {-1 , 0 , 1 , 0 , -1} ; q.push({0 , 0}) ; vis[0][0] = 1 ; while(!q.empty()) { int t = q.top().first , r = q.top().second / n , c = q.top().second % n ; q.pop() ; res = max(res , t) ; if(r == n - 1 && c == n - 1) break ; for(int k = 0 ; k < 4 ; k++) { int nr = r + dir[k] , nc = c + dir[k + 1] ; if(nr < 0 || nr >= n || nc < 0 || nc >= n || vis[nr][nc]) continue; q.push({grid[nr][nc] , nr * n + nc}) ; vis[nr][nc] = 1 ; } } return res; } };
leetcode 778. Swim in Rising Water
原文:https://www.cnblogs.com/mychen06/p/12602866.html