leetcode1034. 边界着色
写出来的总是有莫名的溢出。
直接看题解:
首先要找到包含 (row, col) 的同色连通集 S。
其次在S中找到S的边界,所谓S的边界呢,就是连同集中没有被***格包围的网格。
然后将这些边界的格子染成color。
从(row, col)出发,进行dfs,遍历所有相邻的点。用visited标记访问状态。
如果已经访问过直接返回。
如果颜色不同,直接返回。
如果颜色和起点相同,说明还处于连通集中;
那我们如何判断边界呢?
只需要数相邻的节点是不是4个节点都和自己颜色相同,只要有一个不同,我们就知道这个节点是在边界上的。
当然我们需要标记出来,但如果直接修改则会影响其他节点dfs过程中对边界的判断;所以我们可以用一个「特殊色」,也就是网格中本来不存在的颜色去标记这种边界;
其他dfs判断的时候只要把「起点颜色」和「特殊色」都当作「起点颜色」即可。
最后再把所有「特殊色」换成「目标色」即可。
class Solution {
public:
vector<vector<int>> visited; // 记录单元格是否被访问过
int dx[4] = {1, -1, 0, 0}; // 四个方向的x坐标变化:下、上、右、左
int dy[4] = {0, 0, 1, -1}; // 四个方向的y坐标变化:下、上、右、左
int m; // 网格的行数
int n; // 网格的列数
// 深度优先搜索函数
// si, sj: 当前搜索的单元格坐标
// target: 目标颜色值(需要标记边界的连通分量的颜色)
void dfs(vector<vector<int>>& grid, int si, int sj, int target) {
// 如果当前单元格已被访问过,直接返回
if (visited[si][sj]) return;
// 标记当前单元格为已访问
visited[si][sj] = 1;
// 如果当前单元格颜色不是目标颜色,返回
if (grid[si][sj] != target) return;
int cnt = 0; // 计数器,记录满足条件的相邻单元格数量
// 检查四个方向
for (int d = 0; d < 4; d++) {
int i = si + dx[d]; // 计算相邻单元格的行坐标
int j = sj + dy[d]; // 计算相邻单元格的列坐标
// 检查相邻单元格是否在网格范围内
if (i < m && i >= 0 && j < n && j >= 0) {
// 如果相邻单元格是目标颜色或已被标记为边界(值为0)
if (grid[i][j] == target || grid[i][j] == 0) {
cnt++; // 增加计数器
dfs(grid, i, j, target); // 递归搜索相邻单元格
}
}
}
// 如果四个相邻单元格不都满足条件,则当前单元格是边界
if (cnt != 4) grid[si][sj] = 0; // 标记为边界(暂时用0表示)
}
// 主函数:给网格的连通分量边界着色// row, col: 起始单元格坐标
// color: 要使用的颜色
vector<vector<int>> colorBorder(vector<vector<int>>& grid, int row, int col, int color) {
m = grid.size(); // 获取网格行数
n = grid[0].size(); // 获取网格列数
visited = vector<vector<int>>(m, vector<int>(n, 0)); // 初始化访问矩阵
int target = grid[row][col]; // 获取目标颜色值
// 从起始点开始DFS,标记所有边界单元格为0
dfs(grid, row, col, target);
// 遍历整个网格,将所有标记为0的单元格(边界)着色为目标颜色
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == 0) grid[i][j] = color;
}
}
return grid; // 返回处理后的网格
}
};