洪水填充

洪水填充

  • 设置路径信息进行剪枝和统计,类似感染的过程
  • 路径信息不撤销,可以保证每一片的感染过程能够区分开
  • 遍历次数和样本数量的规模一致

200. 岛屿数量

#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>

using namespace std;

class Solution {
public:
    int rows;
    int columns;

    void dfs(vector<vector<char>> &grid, int row, int col) {
        // 越界或者不是陆地就返回
        if (row < 0 || row >= rows
            || col < 0 || col >= columns
            || grid[row][col] != '1')
            return;
        // 标记这个陆地已经被处理过了
        grid[row][col] = 0;
        dfs(grid, row - 1, col);
        dfs(grid, row + 1, col);
        dfs(grid, row, col - 1);
        dfs(grid, row, col + 1);
    }

    int numIslands(vector<vector<char>> &grid) {
        rows = grid.size();
        columns = grid[0].size();
        int res = 0;

        // 遍历矩阵,对陆地进行 dfs,每次都会遍历这个陆地所在的岛屿
        for (int i = 0; i < rows; ++i) {
            for (int j = 0; j < columns; ++j) {
                if (grid[i][j] == '1') {
                    dfs(grid, i, j);
                    res++;
                }
            }
        }

        return res;
    }
};

130. 被围绕的区域

#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>

using namespace std;

class Solution {
public:
    int rows;
    int columns;

    bool isCoordinateLegal(int row, int col) {
        return row >= 0 && row < rows && col >= 0 && col < columns;
    }

    void convert2F(vector<vector<char>> &board, int row, int col) {
        // 越界或者不是字符 O,就返回
        if (!isCoordinateLegal(row, col) || board[row][col] != 'O') return;
        // 标记成字符 F,表示这片联通的字符 O 是不能被字符 X 完全包围的(有的 O 贴到边界了)
        board[row][col] = 'F';
        convert2F(board, row - 1, col);
        convert2F(board, row + 1, col);
        convert2F(board, row, col - 1);
        convert2F(board, row, col + 1);
    }

    void solve(vector<vector<char>> &board) {
        rows = board.size();
        columns = board[0].size();

        // 第一行和最后一行的 O,是无法被 X 包围的,先把他们所在的联通的 O 区域转换成 F
        for (int j = 0; j < columns; ++j) {
            if (board[0][j] == 'O') convert2F(board, 0, j);
            if (board[rows - 1][j] == 'O') convert2F(board, rows - 1, j);
        }

        // 第一列和最后一列的 O
        for (int i = 0; i < rows; ++i) {
            if (board[i][0] == 'O') convert2F(board, i, 0);
            if (board[i][columns - 1] == 'O') convert2F(board, i, columns - 1);
        }

        // 剩下的联通 O 都是可以被 X 包围的,转换成 X
        // F 是无法被包围的,再变回 O
        for (int i = 0; i < rows; ++i) {
            for (int j = 0; j < columns; ++j) {
                if (board[i][j] == 'O') board[i][j] = 'X';
                if (board[i][j] == 'F') board[i][j] = 'O';
            }
        }
    }
};

827. 最大人工岛

#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>

using namespace std;

class Solution {
public:
    int rows;
    int columns;

    bool isCoordinateLegal(int row, int col) {
        return row >= 0 && row < rows && col >= 0 && col < columns;
    }

    void dfs(vector<vector<int>> &grid, int row, int col, int id) {
        if (!isCoordinateLegal(row, col) || grid[row][col] != 1) return;
        // 标记上 id
        grid[row][col] = id;
        dfs(grid, row - 1, col, id);
        dfs(grid, row + 1, col, id);
        dfs(grid, row, col - 1, id);
        dfs(grid, row, col + 1, id);
    }

    int largestIsland(vector<vector<int>> &grid) {
        int id = 2;
        rows = grid.size();
        columns = grid[0].size();

        // 给不同的岛屿标记上不同 id
        for (int i = 0; i < rows; ++i)
            for (int j = 0; j < columns; ++j)
                if (grid[i][j] == 1)
                    dfs(grid, i, j, id++);

        // 统计每个岛屿大小
        vector<int> sizes(id, 0);
        // res 至少为最大的单独的岛屿大小
        int res = 0;
        for (int i = 0; i < rows; ++i) {
            for (int j = 0; j < columns; ++j) {
                if (grid[i][j] <= 1) continue;
                res = max(res, ++sizes[grid[i][j]]);
            }
        }

        vector<bool> visited(id, false);
        for (int i = 0; i < rows; ++i) {
            for (int j = 0; j < columns; ++j) {
                if (grid[i][j] != 0) continue;
                // 四周的岛屿,0 或者 大于 1
                int up = i > 0 ? grid[i - 1][j] : 0;
                int down = i + 1 < rows ? grid[i + 1][j] : 0;
                int left = j > 0 ? grid[i][j - 1] : 0;
                int right = j + 1 < columns ? grid[i][j + 1] : 0;

                visited[up] = true;
                int merge = 1 + sizes[up];
                if (!visited[down]) {
                    merge += sizes[down];
                    visited[down] = true;
                }
                if (!visited[left]) {
                    merge += sizes[left];
                    visited[left] = true;
                }
                if (!visited[right]) {
                    merge += sizes[right];
                    visited[right] = true;
                }
                res = max(res, merge);
                visited[up] = false;
                visited[down] = false;
                visited[left] = false;
                visited[right] = false;
            }
        }

        return res;
    }
};

803. 打砖块

#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>

using namespace std;

class Solution {
public:
    int rows;
    int columns;

    bool isCoordinateLegal(int row, int col) {
        return row >= 0 && row < rows && col >= 0 && col < columns;
    }

    // 返回转化了多少个砖块
    int convertTo2(vector<vector<int>> &grid, int row, int col) {
        if (!isCoordinateLegal(row, col) || grid[row][col] != 1) return 0;
        grid[row][col] = 2;
        return 1
               + convertTo2(grid, row - 1, col)
               + convertTo2(grid, row + 1, col)
               + convertTo2(grid, row, col - 1)
               + convertTo2(grid, row, col + 1);
    }

    // 判断上下左右是否和标记为 2 的砖块相连
    bool connectTo2(vector<vector<int>> &grid, int row, int col) {
        return (row > 0 && grid[row - 1][col] == 2)
               || (row + 1 < rows && grid[row + 1][col] == 2)
               || (col > 0 && grid[row][col - 1] == 2)
               || (col + 1 < columns && grid[row][col + 1] == 2);
    }

    vector<int> hitBricks(vector<vector<int>> &grid, vector<vector<int>> &hits) {
        rows = grid.size();
        columns = grid[0].size();

        // 依次打出炮弹
        for (auto &hit: hits)
            grid[hit[0]][hit[1]]--;

        // 把打出所有炮弹后仍然和天花板连在一起的连通区域标记成 2
        for (int j = 0; j < columns; ++j)
            convertTo2(grid, 0, j);

        vector<int> res(hits.size(), 0);
        // 倒过来恢复被炮弹打过的地方
        for (int i = hits.size() - 1; i >= 0; i--) {
            int x = hits[i][0];
            int col = hits[i][1];
            grid[x][col]++;
            // 原本炮弹就打空了,不会致使相连的砖块掉落
            if (grid[x][col] <= 0) continue;
            // grid[x][col] 为 1,判断是否与标记成 2 的砖块相连,或者他本身就在天花板最上面
            if (connectTo2(grid, x, col) || x == 0)
                // 除去自身,剩下的才是导致掉下去的砖块
                res[i] = convertTo2(grid, x, col) - 1;
        }
        return res;
    }
};
posted @ 2024-09-08 12:50  n1ce2cv  阅读(7)  评论(0编辑  收藏  举报