洪水填充
- 设置路径信息进行剪枝和统计,类似感染的过程
- 路径信息不撤销,可以保证每一片的感染过程能够区分开
- 遍历次数和样本数量的规模一致
#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;
}
};
#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';
}
}
}
};
#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;
}
};
#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;
}
};