zoukankan      html  css  js  c++  java
  • [LeetCode] 417. Pacific Atlantic Water Flow 太平洋大西洋水流

    Given an m x n matrix of non-negative integers representing the height of each unit cell in a continent, the "Pacific ocean" touches the left and top edges of the matrix and the "Atlantic ocean" touches the right and bottom edges.

    Water can only flow in four directions (up, down, left, or right) from a cell to another one with height equal or lower.

    Find the list of grid coordinates where water can flow to both the Pacific and Atlantic ocean.

    Note:

    1. The order of returned grid coordinates does not matter.
    2. Both m and n are less than 150.

    Example:

    Given the following 5x5 matrix:
    
      Pacific ~   ~   ~   ~   ~ 
           ~  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  *
              *   *   *   *   * Atlantic
    
    Return:
    
    [[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] (positions with parentheses in above matrix).
    

    这道题给了我们一个二维数组,说是数组的左边和上边是太平洋,右边和下边是大西洋,假设水能从高处向低处流,问我们所有能流向两大洋的点的集合。刚开始博主没有理解题意,以为加括号的点是一条路径,连通两大洋的,但是看来看去感觉也不太对,后来终于明白了,是每一个点单独都有路径来通向两大洋。那么就是典型的搜索问题,我最开始想的是对于每个点都来搜索是否能到达边缘,只不过搜索的目标点不再是一个单点,而是所有的边缘点,照这种思路写出的代码无法通过 OJ 大数据集,那么就要想办法来优化代码,优化的方法跟之前那道 Surrounded Regions 很类似,都是换一个方向考虑问题,既然从每个点向中间扩散会 TLE,那么我们就把所有边缘点当作起点开始遍历搜索,然后标记能到达的点为 true,分别标记出 pacific 和 atlantic 能到达的点,那么最终能返回的点就是二者均为 true 的点。我们可以先用DFS来遍历二维数组,参见代码如下:

    解法一:

    class Solution {
    public:
        vector<pair<int, int>> pacificAtlantic(vector<vector<int>>& matrix) {
            if (matrix.empty() || matrix[0].empty()) return {};
            vector<pair<int, int>> res;
            int m = matrix.size(), n = matrix[0].size();
            vector<vector<bool>> pacific(m, vector<bool>(n, false));
            vector<vector<bool>> atlantic(m, vector<bool>(n, false));
            for (int i = 0; i < m; ++i) {
                dfs(matrix, pacific, INT_MIN, i, 0);
                dfs(matrix, atlantic, INT_MIN, i, n - 1);
            }
            for (int i = 0; i < n; ++i) {
                dfs(matrix, pacific, INT_MIN, 0, i);
                dfs(matrix, atlantic, INT_MIN, m - 1, i);
            }
            for (int i = 0; i < m; ++i) {
                for (int j = 0; j < n; ++j) {
                    if (pacific[i][j] && atlantic[i][j]) {
                        res.push_back({i, j});
                    }
                }
            }
            return res;
        }
        void dfs(vector<vector<int>>& matrix, vector<vector<bool>>& visited, int pre, int i, int j) {
            int m = matrix.size(), n = matrix[0].size();
            if (i < 0 || i >= m || j < 0 || j >= n || visited[i][j] || matrix[i][j] < pre) return;
            visited[i][j] = true;
            dfs(matrix, visited, matrix[i][j], i + 1, j);
            dfs(matrix, visited, matrix[i][j], i - 1, j);
            dfs(matrix, visited, matrix[i][j], i, j + 1);
            dfs(matrix, visited, matrix[i][j], i, j - 1);
        }
    };

    那么 BFS 的解法也可以做,用 queue 来辅助,开始把边上的点分别存入 queue 中,然后对应的 map 标记 true,然后开始 BFS 遍历,遍历结束后还是找 pacific 和 atlantic 均标记为 true 的点加入结果 res 中返回即可,参见代码如下:

    解法二:

    class Solution {
    public:
        vector<pair<int, int>> pacificAtlantic(vector<vector<int>>& matrix) {
            if (matrix.empty() || matrix[0].empty()) return {};
            vector<pair<int, int>> res;
            int m = matrix.size(), n = matrix[0].size();
            queue<pair<int, int>> q1, q2;
            vector<vector<bool>> pacific(m, vector<bool>(n, false)), atlantic = pacific;
            for (int i = 0; i < m; ++i) {
                q1.push({i, 0}); 
                q2.push({i, n - 1});
                pacific[i][0] = true;
                atlantic[i][n - 1] = true;
            }
            for (int i = 0; i < n; ++i) {
                q1.push({0, i});
                q2.push({m - 1, i});
                pacific[0][i] = true;
                atlantic[m - 1][i] = true;
            }
            bfs(matrix, pacific, q1);
            bfs(matrix, atlantic, q2);
            for (int i = 0; i < m; ++i) {
                for (int j = 0; j < n; ++j) {
                    if (pacific[i][j] && atlantic[i][j]) {
                        res.push_back({i, j});
                    }
                }
            }
            return res;
        }
        void bfs(vector<vector<int>>& matrix, vector<vector<bool>>& visited, queue<pair<int, int>>& q) {
            int m = matrix.size(), n = matrix[0].size();
            vector<vector<int>> dirs{{0,-1},{-1,0},{0,1},{1,0}};
            while (!q.empty()) {
                auto t = q.front(); q.pop();
                for (auto dir : dirs) {
                    int x = t.first + dir[0], y = t.second + dir[1];
                    if (x < 0 || x >= m || y < 0 || y >= n || visited[x][y] || matrix[x][y] < matrix[t.first][t.second]) continue;
                    visited[x][y] = true;
                    q.push({x, y});
                }
            }
        }
    };

    Github 同步地址:

    https://github.com/grandyang/leetcode/issues/417

    参考资料:

    https://leetcode.com/problems/pacific-atlantic-water-flow/

    https://leetcode.com/problems/pacific-atlantic-water-flow/discuss/90733/java-bfs-dfs-from-ocean

    LeetCode All in One 题目讲解汇总(持续更新中...)

  • 相关阅读:
    开放源码的对象关系映射工具ORM.NET 插入数据 Insert/Update Data
    开放源码的对象关系映射工具ORM.NET 快档开发入门 Quick Start
    .NET 动态脚本语言Script.NET 开发指南
    开放源码的对象关系映射工具ORM.NET 删除数据 Deleting Records using ORM.NET
    .NET Remoting过时了吗?为什么公司的项目还是选择用.NET Remoting,而不是WCF?
    开放源码的对象关系映射工具ORM.NET 查看和显示数据 View and Display data using ORM.NET
    开放源码的对象关系映射工具ORM.NET 查询表 调用存储过程 增加自定义代码
    技术人生:坚持,每日一博
    CQRS:CQRS + DDD + MDP 实现快速应用程序开发
    NodeJs:Happy代码生成器,重构了代码,更新了文档,完善了示例,欢迎下载使用
  • 原文地址:https://www.cnblogs.com/grandyang/p/5962508.html
Copyright © 2011-2022 走看看