题目来源:力扣
在由 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] 是 ‘/’、’’、或 ’ '。
这道题本质上是计算连通分量个数,难点在于理解题意以及确定哪些元素是相连的.
题目使用字符串表示对正方形的划分,若grid.length == n
,则表示将当前单元格划分为 n 2 n^2 n2个小正方形单元格,然后在将每一个小正方形单元格划分两个三角形.如果使用/
划分,则当前小正方形被划分为左上,右下两个三角形,如果使用\
划分,则当前三角形被划分为左下,右上两个三角形.如果使用空格,则表示不对当前小正方形进行划分.题目要求判断划分的区域个数,实际上就是要求计算所有小三角形中的连通分量个数.
注意到一个小三角形可能属于一下四种方位之一,左下,左上,右下,右上.对于未被划分的小三角形,可以将其视作左上,右下划分,不过这两个小三角形是连通的.如果当前小正方形使用/
或\
划分,则被划分后的两个小三角形不是连通的.对于每一个小三角形,除与其位于同一正方形的三角形外,其最多与周围两个三角形连通.例如,位于左下的三角形,如果其左侧有正方形,则其与左侧正方形的一个三角形相连通(右上或右下),如果其下方有正方形,则其余下方正方形的一个三角形相连通(左上或右上).
在理解以上两点后,我们便可以考虑如何计算图中的连通分量个数,此处我们使用并查集计算图中的连通分量个数.
class Solution {
//定义常量表示四个方位
final int left_up = 1;
final int left_down = 2;
final int right_up = 3;
final int right_down = 4;
//将三维坐标转化为一维坐标
private int loc(int x, int y, int z, int gridSize){
return (x*gridSize+y)*2+z;
}
//判断给定的方位是否为左侧,左上或左下
private boolean isLeft(int x){
return x == 1 || x == 2;
}
private boolean isRight(int x){
return x == 3 || x == 4;
}
private boolean isUp(int x){
return x == 1 || x == 3;
}
private boolean isDown(int x){
return x == 2 || x == 4;
}
//使用并查集将当前位置grid[i][j][k]处的三角形与其相邻的两个三角形进行相连
private void unionAdj(UnionFind uf, int[][][] grid, int i, int j, int k){
if(grid[i][j][k] == left_up){
if(j > 0){
//左边的右三角形
if(isRight(grid[i][j-1][0])) //左边
uf.union(loc(i, j-1, 0, grid.length), loc(i, j, k, grid.length));
else
uf.union(loc(i, j-1, 1, grid.length), loc(i, j, k, grid.length));
}
if(i > 0){
//上边的下三角形
if(isDown(grid[i-1][j][0])) //上边
uf.union(loc(i-1, j, 0, grid.length), loc(i, j, k, grid.length));
else
uf.union(loc(i-1, j, 1, grid.length), loc(i, j, k, grid.length));
}
}
else if(grid[i][j][k] == left_down){
if(j > 0){
//左边的右三角形
if(isRight(grid[i][j-1][0])) //左边的右三角形
uf.union(loc(i, j-1, 0, grid.length), loc(i, j, k, grid.length));
else
uf.union(loc(i, j-1, 1, grid.length), loc(i, j, k, grid.length));
}
if(i < grid.length-1){
//下边的上三角形
if(isUp(grid[i+1][j][0])) //下边的上三角形
uf.union(loc(i+1, j, 0, grid.length), loc(i, j, k, grid.length));
else
uf.union(loc(i+1, j, 1, grid.length), loc(i, j, k, grid.length));
}
}
else if(grid[i][j][k] == right_up){
if(i > 0){
if(isDown(grid[i-1][j][0])) //上边的下三角形
uf.union(loc(i-1, j, 0, grid.length), loc(i, j, k, grid.length));
else
uf.union(loc(i-1, j, 1, grid.length), loc(i, j, k, grid.length));
}
if(j < grid.length-1){
if(isLeft(grid[i][j+1][0])) //右边
uf.union(loc(i, j+1, 0, grid.length), loc(i, j, k, grid.length));
else
uf.union(loc(i, j+1, 1, grid.length), loc(i, j, k, grid.length));
}
}
else if(grid[i][j][k] == right_down){
if(i < grid.length-1){
//下边
if(isUp(grid[i+1][j][0]))
uf.union(loc(i+1, j, 0, grid.length), loc(i, j, k, grid.length));
else
uf.union(loc(i+1, j, 1, grid.length), loc(i, j, k, grid.length));
}
if(j < grid.length-1){
//右边
if(isLeft(grid[i][j+1][0]))
uf.union(loc(i, j+1, 0, grid.length), loc(i, j, k, grid.length));
else
uf.union(loc(i, j+1, 1, grid.length), loc(i, j, k, grid.length));
}
}
}
//定义并查集类
class UnionFind{
int[] id;
int count;
public UnionFind(int num){
id = new int[num];
for(int i = 0; i < num; i++)
id[i] = i;
count = num;
}
public int find(int i){
return id[i];
}
public void union(int i, int j){
//System.out.printf("%d, %d\n", i, j);
if(find(i) == find(j)) //已经在同一连通分量中
return;
//将所有连通分量i中的元素全部连接到i所在的连通分量中
int jId = find(j);
for(int k = 0; k < id.length; k++){
if(find(k) == jId)
id[k] = find(i);
}
count--; //连通分量减1
}
public int count(){
return count;
}
}
public int regionsBySlashes(String[] grid) {
int[][][] smallGrid = new int[grid.length][grid.length][2];
//使用并查集搜索连通分量个数
UnionFind uf = new UnionFind(grid.length*grid.length*2);
for(int i = 0; i < grid.length; i++){
for(int j = 0; j < grid[i].length(); j++){
if(grid[i].charAt(j) == '/'){
//划分为左上,右下两部分
smallGrid[i][j][0] = left_up;
smallGrid[i][j][1] = right_down;
}
else if(grid[i].charAt(j) == ' '){
smallGrid[i][j][0] = left_up;
smallGrid[i][j][1] = right_down;
//当前两个三角形是连通的
uf.union(loc(i, j, 0, grid.length), loc(i, j, 1, grid.length));
}
else{
// "\\"
smallGrid[i][j][0] = left_down;
smallGrid[i][j][1] = right_up;
}
}
}
//并查集连接
for(int i = 0; i < grid.length; i++){
for(int j = 0; j < grid.length; j++){
unionAdj(uf, smallGrid, i, j, 0);
unionAdj(uf, smallGrid, i, j, 1);
}
}
return uf.count();
}
}