《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);
            }
        }
    }
};

四.代码讲解

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

  • 方向数组 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] 确保从低处向高处搜索,这与正向水流方向相反,但正是标记能流到海洋的格子的正确方式。

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

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

五、流程图

相关推荐
旖旎夜光2 分钟前
【C++ 基础入门】C++多态(下):单/多继承虚表、多态补充与 21 道高频题
开发语言·c++·笔记·学习
Pniubi8 分钟前
力扣73 矩阵置零
算法·leetcode·矩阵
apcipot_rain10 小时前
C++转Java日记(03)
java·开发语言·c++
布莱克60510 小时前
C++ 中 map 的 insert 与 emplace:key 已存在时会覆盖吗?
开发语言·数据结构·c++·算法·map
xys_67811 小时前
深挖C++:类和对象(中)
开发语言·c++
D e re k ZH13 小时前
C++ 系统学习手记:从语法细节到工程实践
开发语言·数据结构·c++·算法
石小石Orz14 小时前
AI 正在蚕食我们的编码能力
前端·后端·算法
xiaoye-duck14 小时前
《C++ 项目:手写大模型接入 SDK》Ollama接口设计(上):初始化、全量响应实现和测试
开发语言·网络·c++·语言模型
zaizai100715 小时前
【Effective Modern C++】学习第一章
c++