LeetCode417. 太平洋大西洋水流问题

本文讨论了解决LeetCode417题太平洋大西洋水流问题的算法,通过深度优先搜索(DFS)策略,分析如何确定哪些网格坐标可以让雨水同时流向太平洋和大西洋。提供了一种优化的DFS方法,避免了常规方法可能导致的超时问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述


LeetCode417. 太平洋大西洋水流问题


题目:

  • 有一个 m × n 的矩形岛屿,与 太平洋大西洋 相邻。 “太平洋” 处于大陆的左边界和上边界,而 “大西洋” 处于大陆的右边界和下边界。
  • 这个岛被分割成一个由若干方形单元格组成的网格。给定一个 m x n 的整数矩阵 heightsheights[r][c] 表示坐标 (r, c) 上单元格 高于海平面的高度
  • 岛上雨水较多,如果相邻单元格的高度 小于或等于 当前单元格的高度,雨水可以直接向北、南、东、西流向相邻单元格。水可以从海洋附近的任何单元格流入海洋。
  • 返回网格坐标 result2D 列表 ,其中 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;
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值