題目連接: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; } }