在由
1
×
1
1 \times 1
1×1 方格组成的
N
×
N
N \times N
N×N 网格
g
r
i
d
grid
grid 中,每个
1
×
1
1 \times 1
1×1 方块由 /
、\
或空格构成。这些字符会将方块划分为一些共边的区域。
(请注意,反斜杠字符是转义的,因此 \
用 “\\
” 表示。)。
返回区域的数目。
示例 1:
输入:
[
" /",
"/ "
]
输出:2
解释:2x2 网格如下:
示例 2:
输入:
[
" /",
" "
]
输出:1
解释:2x2 网格如下:
示例 3:
输入:
[
"\\/",
"/\\"
]
输出:4
解释:(回想一下,因为 \ 字符是转义的,所以 “\/” 表示 /,而 “/\” 表示 /\。)
2x2 网格如下:
示例 4:
输入:
[
"/\\",
"\\/"
]
输出:5
解释:(回想一下,因为 \ 字符是转义的,所以 “/\” 表示 /\,而 “\/” 表示 /。)
2x2 网格如下:
示例 5:
输入:
[
"//",
"/ "
]
输出:3
解释:2x2 网格如下:
提示:
1
<
=
g
r
i
d
.
l
e
n
g
t
h
=
=
g
r
i
d
[
0
]
.
l
e
n
g
t
h
<
=
30
1 <= grid.length == grid[0].length <= 30
1<=grid.length==grid[0].length<=30
g
r
i
d
[
i
]
[
j
]
grid[i][j]
grid[i][j] 是 /
、\
、或 。
思路
「斜杠」、「反斜杠」把单元格拆分成的
2
2
2 个三角形的形态,在做合并的时候需要分类讨论。根据「斜杠」、「反斜杠」分割的特点,我们把一个单元格分割成逻辑上的 4 个部分。如下图所示:
我们须要遍历一次输入的二维网格 g r i d grid grid,在 单元格内 和 单元格间 进行合并。
单元格内:
- 如果是空格:合并 0 、 1 、 2 、 3 0、1、2、3 0、1、2、3;
- 如果是斜杠:合并 0 、 3 0、3 0、3,合并 1 、 2 1、2 1、2;
- 如果是反斜杠:合并
0
、
1
0、1
0、1,合并
2
、
3
2、3
2、3。
单元格间:
我们选择在遍历
g
r
i
d
grid
grid 的每一个单元格的时候,分别向右、向下尝试合并。
- 向右:合并 1 1 1 (当前单元格)和 3 3 3(当前单元格右边 1 1 1 列的单元格),上图中红色部分;
- 向下:合并
2
2
2 (当前单元格)和
0
0
0(当前单元格下边
1
1
1 列的单元格),上图中蓝色部分。
并查集里连通分量的个数就是题目要求的区域的个数。
class Solution {
public:
int find(vector<int>&f,int x){
return f[x]==x?x:f[x]=find(f,f[x]);
}
void union1(vector<int>&f,int x,int y){
x=find(f,x);
y=find(f,y);
f[x]=y;
}
int regionsBySlashes(vector<string>& grid) {
int n=grid.size();
vector<int>f(n*n*4);
for (int i=0;i<n*n*4;i++){
f[i]=i;
}
for (int i=0;i<n;i++){
for (int j=0;j<n;j++){
int idx=i*n+j;
if (i<n-1){
union1(f,idx*4+2,(idx+n)*4);
}
if (j<n-1){
union1(f,idx*4+1,(idx+1)*4+3);
}
if (grid[i][j]=='/'){
union1(f,idx*4+1,idx*4+2);
union1(f,idx*4,idx*4+3);
}else if (grid[i][j]=='\\'){
union1(f,idx*4+1,idx*4);
union1(f,idx*4+2,idx*4+3);
}else{
union1(f,idx*4,idx*4+1);
union1(f,idx*4+1,idx*4+2);
union1(f,idx*4+2,idx*4+3);
}
}
}
int res=0;
for (int i=0;i<n*n*4;i++){
if (find(f,i)==i) res++;
}
return res;
}
};