题目连接:regions-cut-by-slashesjava
在由 1 x 1 方格组成的 N x N 网格 grid 中,每一个 1 x 1 方块由 /、 或空格构成。这些字符会将方块划分为一些共边的区域。(请注意,反斜杠字符是转义的,所以 用 "\" 表示。)。返回区域的数目。c++
因为每一个小区域只填充'/'或者'',所以,小区域划分最多有三种状况(编号如上图所示):算法
相邻区域间,他们的编号小区域存在必定会在同一个块的状况。其中:数组
咱们开始给每一个小区域编一个惟一的块号,经过遍历区域,达到数出所有惟一块的数目。ui
class Solution { private int[] grids; // 用数组来表示块编号 private int num; // 统计惟一块的数目 public int regionsBySlashes(String[] grid) { int N = grid.length; buildUnionFind(N); // 遍历合并全部的区域 for (int r = 0; r < grid.length; r++) for (int c = 0; c < grid[r].length(); c++) process(r, c, N, grid[r].charAt(c)); return num; } // 构建并查集,初始每一个块有一个惟一编号 private void buildUnionFind(int N) { grids = new int[N * N * 4]; num = N * N * 4; for (int i = 0; i < grids.length; i++) grids[i] = i; } // 根据行和列的序号,获得块在数组中的位置 private int getSubSquare(int r, int c, int N, int ith) { return r * N * 4 + c * 4 + ith; } // 寻找块的根编号 private int find(int p) { while (grids[p] != p) { grids[p] = grids[grids[p]]; p = grids[p]; } return p; } // 合并两个块 private void union(int p, int q) { int rootP = find(p); int rootQ = find(q); if (rootP != rootQ) num--; // 若是两个块拥有不一样的编号,合并后,惟一块的数目减1 grids[rootP] = rootQ; } private void process(int r, int c, int N, char square) { // 获取区域中四个小区域的块编号 int s0 = getSubSquare(r, c, N, 0); int s1 = getSubSquare(r, c, N, 1); int s2 = getSubSquare(r, c, N, 2); int s3 = getSubSquare(r, c, N, 3); // 同一个区域的小区域合并 switch(square) { case '\\': union(s0, s2); union(s1, s3); break; case '/': union(s0, s1); union(s2, s3); break; default: union(s0, s1); union(s1, s2); union(s2, s3); } // 相邻区域的合并 if (r > 0) { union(s0, getSubSquare(r - 1, c, N, 3)); } if (r < N - 1) { union(s3, getSubSquare(r + 1, c, N, 0)); } if (c > 0) { union(s1, getSubSquare(r, c - 1, N, 2)); } if (c < N - 1) { union(s2, getSubSquare(r, c + 1, N, 1)); } } }
咱们很难从原图中,将该图转化成一个用数字表示的数组。可是,当咱们将原图表示成一个规模*2的数组时,他将能够表示以下:code
0 1 0 1 ["//", "/ "] => 1 0 1 0 0 1 0 0 1 0 0 0
咱们将数字1当作一道墙,数字0当作一个空白块,则没有墙相隔的块,他们属于同一个惟一块。从上数字中,咱们能够直观的看出,一共存在3个惟一块。可是这时,属于同一个惟一空白块的小空白块他们可能还不相邻(即在斜对角线上)。咱们再把原图表示成一个规模*3数组,表示以下:blog
0 0 1 0 0 1 0 1 0 0 1 0 ["//", "/ "] => 1 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0
这时,能够清楚的看出,一共存在3个惟一空白块,且在同一个惟一空白块的全部小空白块,都是相邻的了。这个时候,咱们就能够采用深度优先搜索,从数组的边界开始,遍历存在多少个不相邻的0,便可获得答案。leetcode
class Solution { int[][] grids; // 表示原图的数组 public int regionsBySlashes(String[] grid) { buildGrids(grid); int count = 0; // 深搜遍历 for (int r = 0; r < grids.length; r++) { for (int c = 0; c < grids[r].length; c++) { count += dfs(r, c); } } return count; } // 将原图表示成规模*3的数组 private void buildGrids(String[] grid) { int N = grid.length; grids = new int[N * 3][N * 3]; for (int i = 0; i < grid.length; i++) { for (int j = 0; j < grid[i].length(); j++) { if (grid[i].charAt(j) == '/') { grids[i * 3 + 2][j * 3] = 1; grids[i * 3 + 1][j * 3 + 1] = 1; grids[i * 3][j * 3 + 2] = 1; } else if (grid[i].charAt(j) == '\\') { grids[i * 3][j * 3] = 1; grids[i * 3 + 1][j * 3 + 1] = 1; grids[i * 3 + 2][j * 3 + 2] = 1; } } } } private int dfs(int r, int c) { // 越界返回0 if (r < 0 || r >= grids.length || c < 0 || c >= grids[r].length) return 0; // 遇到墙(数字1)返回0 if (grids[r][c] == 1) return 0; // 将空白块改成1,并向他四周遍历,结果返回1 grids[r][c] = 1; dfs(r - 1, c); dfs(r + 1, c); dfs(r, c - 1); dfs(r, c + 1); return 1; } }