uacs2024

导航

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

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

写出来的很多bug。直接看题解。

dfs题解

算法思路解释:

  1. 逆向思维:不是从每个单元格出发寻找是否能到达海洋,而是从海洋边界出发,逆向寻找可以流向海洋的单元格。

  2. 两个标记矩阵

    • toPacific:记录能流向太平洋的单元格

    • toAtlantic:记录能流向大西洋的单元格

  3. DFS搜索过程

    • 从太平洋边界(矩阵左边界和上边界)开始DFS,标记所有能流向太平洋的单元格

    • 从大西洋边界(矩阵右边界和下边界)开始DFS,标记所有能流向大西洋的单元格

    • 水只能从高往低流或平流,所以搜索条件是heights[newX][newY] >= heights[x][y]

  4. 结果收集

    • 遍历所有单元格,找出同时被两个矩阵标记的单元格

    • 这些单元格就是能同时流向太平洋和大西洋的单元格

关键点说明:

  • 方向数组:使用dXdY数组可以方便地处理四个方向的移动

  • 边界处理:DFS从边界开始,因为边界单元格直接与海洋相连

  • 避免重复:在遍历边界时跳过角落单元格,避免重复处理

  • 逆向思维:这种方法比从每个单元格出发正向搜索更高效,时间复杂度为O(mn)

class Solution {
public:
    int m, n; // m是矩阵行数,n是矩阵列数
    int dX[4] = {0, 0, 1, -1}; // 四个方向的x坐标变化:右、左、下、上
    int dY[4] = {1, -1, 0, 0}; // 四个方向的y坐标变化:右、左、下、上

    // 深度优先搜索函数,标记可以流向某个海洋的单元格
    void dfs(int x, int y, vector<vector<int>>& heights, vector<vector<bool>>& ocean) {
        // 如果当前单元格已经被标记过,直接返回
        if (ocean[x][y]) return;
        
        // 标记当前单元格为可流向该海洋
        ocean[x][y] = true;
        
        // 探索四个方向
        for (int i = 0; i < 4; ++i) {
            int newX = x + dX[i]; // 计算新的行坐标
            int newY = y + dY[i]; // 计算新的列坐标
            
            // 检查新坐标是否在矩阵范围内
            if (newX >= 0 && newX < m && newY >= 0 && newY < n) {
                // 只有当新单元格高度≥当前单元格高度时才继续搜索
                // (因为水只能从高往低流或平流)
                if (heights[newX][newY] >= heights[x][y]) {
                    dfs(newX, newY, heights, ocean);
                }
            }
        }
    }

    vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {
        m = heights.size(); // 获取行数
        n = heights[0].size(); // 获取列数
        
        // 创建两个矩阵来记录能流向太平洋和大西洋的单元格
        vector<vector<bool>> toPacific(m, vector<bool>(n, false)); // 太平洋可达性
        vector<vector<bool>> toAtlantic(m, vector<bool>(n, false)); // 大西洋可达性
        
        // 从太平洋边界(左边界和上边界)开始DFS
        for (int i = 0; i < m; ++i) dfs(i, 0, heights, toPacific); // 左边界
        for (int j = 1; j < n; ++j) dfs(0, j, heights, toPacific); // 上边界(跳过(0,0)避免重复)
        
        // 从大西洋边界(右边界和下边界)开始DFS
        for (int i = 0; i < m; ++i) dfs(i, n - 1, heights, toAtlantic); // 右边界
        for (int j = 0; j < n - 1; ++j) dfs(m - 1, j, heights, toAtlantic); // 下边界(跳过(m-1,n-1)避免重复)
        
        // 收集能同时流向两个海洋的单元格
        vector<vector<int>> res;
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (toAtlantic[i][j] && toPacific[i][j]) {
                    res.push_back({i, j}); // 如果能同时流向两个海洋,加入结果
                }
            }
        }
        
        return res;
    }
};

 deepseek v3写的BFS版本:

class Solution {
public:
    int m, n; // 矩阵的行数和列数
    int dX[4] = {0, 0, 1, -1}; // 四个方向的x坐标变化:右、左、下、上
    int dY[4] = {1, -1, 0, 0}; // 四个方向的y坐标变化:右、左、下、上

    // BFS函数,用于标记可以流向某个海洋的单元格
    void bfs(queue<pair<int, int>>& q, vector<vector<int>>& heights, vector<vector<bool>>& ocean) {
        while (!q.empty()) {
            auto [x, y] = q.front();
            q.pop();
            
            // 如果当前单元格已经被标记过,跳过
            if (ocean[x][y]) continue;
            
            // 标记当前单元格为可流向该海洋
            ocean[x][y] = true;
            
            // 探索四个方向
            for (int i = 0; i < 4; ++i) {
                int newX = x + dX[i];
                int newY = y + dY[i];
                
                // 检查新坐标是否在矩阵范围内
                if (newX >= 0 && newX < m && newY >= 0 && newY < n) {
                    // 只有当新单元格高度≥当前单元格高度时才加入队列
                    // (因为水只能从高往低流或平流)
                    if (heights[newX][newY] >= heights[x][y] && !ocean[newX][newY]) {
                        q.push({newX, newY});
                    }
                }
            }
        }
    }

    vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {
        m = heights.size(); // 获取行数
        n = heights[0].size(); // 获取列数
        
        // 创建两个矩阵来记录能流向太平洋和大西洋的单元格
        vector<vector<bool>> toPacific(m, vector<bool>(n, false));
        vector<vector<bool>> toAtlantic(m, vector<bool>(n, false));
        
        // 创建两个队列用于BFS
        queue<pair<int, int>> pacificQueue;
        queue<pair<int, int>> atlanticQueue;
        
        // 初始化太平洋队列(左边界和上边界)
        for (int i = 0; i < m; ++i) pacificQueue.push({i, 0});
        for (int j = 1; j < n; ++j) pacificQueue.push({0, j});
        
        // 初始化大西洋队列(右边界和下边界)
        for (int i = 0; i < m; ++i) atlanticQueue.push({i, n - 1});
        for (int j = 0; j < n - 1; ++j) atlanticQueue.push({m - 1, j});
        
        // 执行BFS搜索
        bfs(pacificQueue, heights, toPacific);
        bfs(atlanticQueue, heights, toAtlantic);
        
        // 收集能同时流向两个海洋的单元格
        vector<vector<int>> res;
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (toAtlantic[i][j] && toPacific[i][j]) {
                    res.push_back({i, j});
                }
            }
        }
        
        return res;
    }
};

 

posted on 2025-03-28 20:05  ᶜʸᵃⁿ  阅读(25)  评论(0)    收藏  举报