《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] 判断,而当前格子已在进入时标记,因此不会重复。

五、流程图

相关推荐
Hhy_110712 小时前
《C++深度解构02》类和对象(上)——定义规范、内存对齐与 this 指针全解
c语言·开发语言·c++·学习·visual studio
晚风叙码12 小时前
C++哈希表实现:开放定址法和链地址法 (哈希桶)
数据结构·c++·哈希算法·散列表
逆境不可逃12 小时前
LeetCode 双题:415. 字符串相加与 143. 重排链表
算法
2601_9507607913 小时前
TNF-α:自身免疫疾病治疗的核心靶点与信号通路解析
人工智能·算法·蛋白
呜喵王阿尔萨斯13 小时前
C/C++ 杂记-1
c++
不会代码的小猴13 小时前
2. 了解Qt
开发语言·c++·笔记·qt·算法
比奇堡裤头村13 小时前
统计学习方法——支持向量机
算法·支持向量机·学习方法
兵哥工控13 小时前
mfc实现在数值范围内实时改变静态文本控件字体颜色实例
c++·mfc
程序喵大人15 小时前
【C++进阶】STL算法与函数对象 - 09 函数对象保存状态并复用规则
开发语言·c++·算法·stl·函数对象
致Great20 小时前
DeepSeek Harness插件开发实战教程:我让它自己写了一个 arXiv 搜索插件
算法