《LeetCode 417 太平洋大西洋水流问题 FloodFill DFS 解法》

一.题目

417. 太平洋大西洋水流问题 - 力扣(LeetCode)

二.思路讲解

2.1 审题

本题要求找出矩阵中所有能够同时流向太平洋和大西洋 的格子。水可以从一个格子流向上下左右 相邻的格子,条件是相邻格子的高度 ≤ 当前格子的高度 。太平洋位于矩阵的上边界和左边界 ,大西洋位于下边界和右边界

2.2 思路讲解

直接判断每个格子是否能同时流向两个海洋比较困难,但可以采用正难则反 的思路:从海洋出发,反向标记能流到海洋的格子。具体做法:

  • 从太平洋边界(上、左)出发,反向进行深度优先搜索(DFS),标记所有能流到太平洋的格子。反向搜索时,水可以从低处流向高处,即相邻格子高度 ≥ 当前格子高度时才能流动。

  • 从大西洋边界(下、右)出发,同样反向搜索,标记所有能流到大西洋的格子。

  • 最后,同时被两个海洋标记的格子就是既能流向太平洋又能流向大西洋的格子。

三.代码演示

cpp 复制代码
class Solution 
{
public:
    int row,col;
    int bx[4] = {0,0,1,-1};
    int by[4] = {1,-1,0,0};
    vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights)
    {
        row = heights.size();col = heights[0].size();
        vector<vector<bool>>Pac(row,vector<bool>(col));
        vector<vector<bool>>Atl(row,vector<bool>(col));
        //处理太平洋
        for(int j = 0;j < col;j++) dfs(heights,0,j,Pac);
        for(int i = 0;i < row;i++) dfs(heights,i,0,Pac);
        //处理大西洋
        for(int i = 0;i < row;i++) dfs(heights,i,col - 1,Atl);
        for(int j = 0;j < col;j++) dfs(heights,row - 1,j,Atl);
        //处理二者相交部分
        vector<vector<int>> ret;
        for(int i = 0;i < row;i++)
        {
            for(int j = 0;j < col;j++)
            {
                if(Pac[i][j] && Atl[i][j])
                {
                    ret.push_back({i,j});
                }
            }
        }
        return ret;
    }
    void dfs(vector<vector<int>>& heights,int i,int j,vector<vector<bool>>& cur)
    {
        cur[i][j] = true;
        for(int k = 0;k < 4;k++)
        {
            int x = i + bx[k],y = j + by[k];
            if(x >= 0 && y >= 0 && x < row && y < col && !cur[x][y] && heights[i][j] <= heights[x][y])
            {
                dfs(heights,x,y,cur);
            }
        }
    }
};

四.代码讲解

一、全局变量与方向数组
  • rowcol:成员变量,存储网格的行数和列数。

  • 方向数组 bx[4]by[4]:表示上下左右四个方向的偏移量,用于探索相邻格子。

二、主函数 pacificAtlantic
  1. 获取网格尺寸row = heights.size(); col = heights[0].size();

  2. 初始化两个布尔矩阵

    • Pac:记录能流到太平洋的格子,初始全 false

    • Atl:记录能流到大西洋的格子,初始全 false

  3. 从太平洋边界出发进行反向DFS

    • 遍历第一行(i = 0)的所有列,调用 dfs(heights, 0, j, Pac)

    • 遍历第一列(j = 0)的所有行,调用 dfs(heights, i, 0, Pac)

    • 注意:左上角格子 (0,0) 会被调用两次,但 dfs 内会检查 cur[i][j],已访问则直接返回,不会重复。

  4. 从大西洋边界出发进行反向DFS

    • 遍历最后一行(i = row-1)的所有列,调用 dfs(heights, i, col-1, Atl)

    • 遍历最后一列(j = col-1)的所有行,调用 dfs(heights, row-1, j, Atl)

  5. 收集既能流向太平洋又能流向大西洋的格子

    • 遍历整个网格,如果 Pac[i][j]Atl[i][j] 都为 true,则将坐标 {i, j} 加入结果集。

    • 返回结果集。

三、递归函数 dfs

dfs(heights, i, j, cur) 从格子 (i, j) 开始,反向标记所有能流到当前海洋的格子。执行流程:

  1. 标记当前格子cur[i][j] = true,表示该格子能流向对应的海洋。

  2. 向四个方向探索 :遍历四个方向,计算新坐标 (x, y)

    • 边界检查x >= 0 && y >= 0 && x < row && y < col

    • 未访问!cur[x][y]

    • 反向流动条件heights[i][j] <= heights[x][y]

      • 正向水从高处流向低处(h_current >= h_neighbor)。

      • 反向搜索时,如果邻居的高度 大于等于 当前格子,则水可以从邻居流向当前格子,因此当前格子能流向海洋 → 邻居也能流向海洋。

  3. 若满足条件,则递归调用 dfs(heights, x, y, cur),继续标记。

四、关键细节
  • 反向搜索的条件heights[i][j] <= heights[x][y] 确保从低处向高处搜索,这与正向水流方向相反,但正是标记能流到海洋的格子的正确方式。

  • 标记数组重用PacAtl 既是访问标记,也是最终结果标记,节省空间。

  • 避免重复访问 :在递归入口先检查 cur[i][j],但代码中是在递归调用时用 !cur[x][y] 判断,而当前格子已在进入时标记,因此不会重复。

五、流程图

相关推荐
Jerry31 分钟前
LeetCode 1002. 查找共用字符
算法
无限的鲜花1 小时前
协程本质是函数加状态机——零基础深入浅出 C++20 协程
c++·算法·c++20
精明的身影1 小时前
C++自学之路1:Hello world
开发语言·c++
旖-旎1 小时前
《LeetCode 64 最小路径和 || LeetCode 174 地下城游戏》
c++·算法·leetcode·动态规划
森林古猿11 小时前
再论斜率优化
c++·学习·算法
万法若空2 小时前
【数学-简单数论】同余中的逆
线性代数·算法
水利行业RTU手艺人2 小时前
RTU固件中的“数据保险箱”——离线数据补发系统设计
c++·stm32·单片机·物联网
凯瑟琳.奥古斯特2 小时前
力扣1009补码解法C++实现
开发语言·c++·算法·leetcode·职场和发展
KaMeidebaby3 小时前
卡梅德生物技术快报|蛋白的叠氮基修饰:实操解析:核酸模板耦合蛋白的叠氮基修饰实现靶蛋白定点共价标记
前端·人工智能·物联网·算法·百度
通信仿真爱好者4 小时前
第【60期】--大规模MIMO系统信号检测算法误码率比较 --matlab完整代码+参考文章
算法·matlab·mimo·信号检测