出处
作者:yexiso
链接:https://leetcode-cn.com/problems/regions-cut-by-slashes/solution/tu-jie-bing-cha-ji-he-bing-ding-dian-by-bb22r/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
题目
在由 1 x 1 方格组成的 N x N 网格 grid 中,每个 1 x 1 方块由 /、\ 或空格构成。这些字符会将方块划分为一些共边的区域。
(请注意,反斜杠字符是转义的,因此 \ 用 “\” 表示。)。
返回区域的数目。
示例 1:
输入: [ " /", "/ " ]
输出:2 解释:2x2 网格如下:
示例 2:
输入: [ " /", " " ] 输出:1
解释:2x2 网格如下:
示例 3:
输入: [ “\/”, “/\” ] 输出:4
解释:(回想一下,因为 \ 字符是转义的,所以 “\/” 表示 /,而
“/\” 表示 /\。) 2x2 网格如下:
示例 4:
输入: [ “/\”, “\/” ] 输出:5
解释:(回想一下,因为 \ 字符是转义的,所以 “/\” 表示 /\,而
“\/” 表示 /。) 2x2 网格如下:
示例 5:
输入: [ “//”, "/ " ] 输出:3
解释:2x2 网格如下:
提示:
1 <= grid.length == grid[0].length <= 30 grid[i][j] 是 ‘/’、’’、或 ’ '。
分析
转化思路
要判断一个正方形被分割成了多少个区域,我们可以通过判断正方形内部有多少个封闭区域。
而要判断区域是否封闭,怎么办?明显,我们可以使用并查集:我们只需要访问区域的每个顶点,判断这些顶点是否构成环即可,如果构成环,便形成了封闭区域。
如何使用并查集判断单个连通分量中是否形成环? 那就很简单了:只需要在合并两个顶点时,判断两个顶点是否同源(根节点相同)
所以我们将一个 N x N 正方形划分成 (N + 1) * (N + 1) 个顶点,然后根据正方形中的 \ 和 /
来对顶点进行合并,同时判断形成了多少个封闭区域即可,具体过程见图例。
步骤
- 计算网格大小 N,给网格添加 N+1 的平方个顶点,并进行编号;
- 构建并查集,将网格的所有边缘节点合并。这里的边缘节点是指位于网格边缘上的顶点;
- 遍历字符串数组 grid 中的字符,并作如下判断:
- 如果字符为空格 ,跳过,
- 如果字符为 /,将小网格的 左下 和 右上 两个顶点合并,
- 如果字符为 \,将小网格的 左上 和 右下 两个顶点合并。
- 如果两个顶点不同源(根节点不同),合并,区域数不变;
- 如果两个顶点同源(根节点相同),区域数 + 1;
- 最后判断生成了多少个封闭区域。
代码
// 并查集常规模版
class Djset {
public:
vector<int> parent; // 记录父节点
vector<int> rank; // 记录节点的秩
int count; // 记录区域数
Djset(int n): parent(n), rank(n), count(1) {
for (int i = 0; i < n; i++) parent[i] = i;
}
// 查找
int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]);
}
return parent[x];
}
// 合并
void merge(int x, int y) {
int rootx = find(x);
int rooty = find(y);
if (rootx != rooty) {
if (rank[rootx] < rank[rooty]){
swap(rootx, rooty);
}
parent[rooty] = rootx;
if (rank[rootx] == rank[rooty]) rank[rootx] += 1;
} else {
count++;
}
}
int getCount() {
return count;
}
};
class Solution {
public:
int regionsBySlashes(vector<string>& grid) {
int n = grid.size();
if (n == 0) return 0;
// m : 每行顶点数目
int m = n + 1;
// num : 顶点总数
int num = m * m;
// 初始化: 将所有边缘合并
Djset ds(num + 1);
for (int i = 0; i < num; i++) {
if (i / m == 0 || i / m == m - 1 || i % m == 0 || i % m == m - 1) ds.merge(num, i);
}
// 访问每个小网格
for (int r = 0; r < n; r++) {
auto s = grid[r];
for (int c = 0; c < s.size(); c++) {
if (s[c] == '/') ds.merge((r + 1) * m + c, r * m + c + 1);
else if (s[c] == '\\') ds.merge(r * m + c, (r + 1) * m + c + 1);
}
}
return ds.getCount();
}
};