1. 程式人生 > 其它 >演算法練習帖--56--由斜槓劃分區域(Java)

演算法練習帖--56--由斜槓劃分區域(Java)

技術標籤:演算法dfsbfs

由斜槓劃分區域(並查集、DFS、BFS)

一、題目簡介

在由 1 x 1 方格組成的 N x N 網格 grid 中,每個 1 x 1 方塊由 /、\ 或空格構成。這些字元會將方塊劃分為一些共邊的區域。

(請注意,反斜槓字元是轉義的,因此 \ 用 “\” 表示。)。

返回區域的數目。
(題目來源:力扣(LeetCode)

示例 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] 是 '/'、'\'、或 ' '。

二、解決方法

1. 並查集(官方題解)

package com.lxf.uf;

public class RegionsBySlashes {
    public int regionsBySlashes(String[] grid) {
        //獲取網格長
        int length=grid.length;
        //因為是正方形所以寬也是length,而且由4*length*length小正方形組成
        int
size=4*length*length; //初始化並查集物件 UnionFind uf = new UnionFind(size); for (int i = 0; i < length; i++) { //轉字串為字元陣列 char[] chars = grid[i].toCharArray(); for (int j = 0; j < chars.length; j++) { //將二維網格轉換為一維網格 int index=4*(i*length+j); //獲取當前字元 char c=chars[j]; //單元格內合併 if(c=='/'){ //合併0,3 uf.union(index,index+3); //合併1,2 uf.union(index+1,index+2); }else if(c=='\\'){ //合併0,1 //合併2,3 uf.union(index,index+1); uf.union(index+2,index+3); }else{ //合併0,1,2,3 uf.union(index,index+1); uf.union(index+1,index+2); uf.union(index+2,index+3); } //單元格間合併 if(j+1<length){ //合併當前正方形1和下一個正方形的3 uf.union(index+1,index+7); } if(i+1<length){ //合併當前正方形2和下一個正方形的0 uf.union(index+2,index+4*length); } } } return uf.getCount(); } class UnionFind{ int count; int[] parent; int[] rank; public int getCount() { return count; } /** * 初始化方法 * @param length */ public UnionFind(int length) { parent=new int[length]; rank=new int[length]; count=length; for (int i = 0; i < length; i++) { parent[i]=i; } } /** * 查詢父親結點方法 * @param index * @return */ public int find(int index){ while (index!=parent[index]){ parent[index]=parent[parent[index]]; index=parent[index]; } return index; } /** * 合併方法 * @param index1 要合併的第一個集合下標 * @param index2 要合併的第二個集合下標 */ public void union(int index1,int index2){ //找到對應的父結點 int root1=find(index1); int root2=find(index2); if(root1==root2) return; //按秩合併 if(rank[root1]>rank[root2]){ parent[root2]=root1; }else if(rank[root1]<rank[root2]){ parent[root1]=root2; }else{ parent[root2]=root1; rank[root1]++; } count--; } } }

在寫BFS和DFS的之前看一段大佬的解析就豁然開朗了:每個小格分解為 3 * 3 方格,BFS和DFS求連通分量思路。

2. BFS

package com.lxf.test;

public class RegionsBySlashes {
    public static void main(String[] args) {

    }
    private static   int tupleL;
    public static int regionsBySlashes(String[] grid) {
        //獲取網格長
        int l=grid.length;
        tupleL=3*l;
        //新建3*3*length*length小正方形陣列
        int[][] tuple = new int[tupleL][tupleL];
        for (int i = 0; i < l; i++) {
            //轉字串為字元陣列
            char[] chars = grid[i].toCharArray();
            for (int j = 0; j < chars.length; j++) {
                //獲取當前字元
                char c=chars[j];
                //根據字元給陣列附上初始值:0是空出來的小正方型,是可以連通的;1是斜線,阻隔小正方型的。
                //或者比作第200道題目:0是小島,1是水域(我這反過來是因為陣列初始值就是0)
                if(c=='/'){
                    //將9個小正方形按/劃開
                    tuple[i*3][j*3+2]=1;
                    tuple[i*3+1][j*3+1]=1;
                    tuple[i*3+2][j*3]=1;
                }else if(c=='\\'){
                    //將9個小正方形按\劃開
                    tuple[i*3][j*3]=1;
                    tuple[i*3+1][j*3+1]=1;
                    tuple[i*3+2][j*3+2]=1;
                }
            }
        }
        //DFS求連通量
        int count=0;
        for (int i = 0; i <  l*3; i++) {
            for (int j = 0; j < l*3; j++) {
                    if(tuple[i][j]==0){
                        count++;
                        dfs(tuple,i,j);
                    }
            }
        }
        return count;
    }

    /**
     * 深度搜索演算法
     * @param tuple
     * @param i
     * @param j
     */
    private static void dfs(int[][] tuple, int i, int j) {
        //結束條件
        if(i<0||j<0||i>=tupleL||j>=tupleL||tuple[i][j]==1){
            return;
        }
        tuple[i][j]=1;
        //上下左右搜尋
        dfs(tuple,i-1,j);
        dfs(tuple,i+1,j);
        dfs(tuple,i,j-1);
        dfs(tuple,i,j+1);
    }

}

3.BFS

package com.lxf.bfs;

import java.util.LinkedList;
import java.util.Queue;

public class RegionsBySlashes {
    //(9*grid.length*grid.length)個小正方型組成的大正方型的邊長
    private static  int tupleL;
    public static int regionsBySlashes(String[] grid) {
        //獲取網格長
        int l=grid.length;
        tupleL=3*l;
        //新建3*3*length*length小正方形陣列
        int[][] tuple = new int[tupleL][tupleL];
        for (int i = 0; i < l; i++) {
            //轉字串為字元陣列
            char[] chars = grid[i].toCharArray();
            for (int j = 0; j < chars.length; j++) {
                //獲取當前字元
                char c=chars[j];
                //根據字元給陣列附上初始值:0是空出來的小正方型,是可以連通的;1是斜線,阻隔小正方型的。
                //或者比作第200道題目:0是小島,1是水域(我這反過來是因為陣列初始值就是0)
                if(c=='/'){
                    //將9個小正方形按/劃開
                    tuple[i*3][j*3+2]=1;
                    tuple[i*3+1][j*3+1]=1;
                    tuple[i*3+2][j*3]=1;
                }else if(c=='\\'){
                    //將9個小正方形按\劃開
                    tuple[i*3][j*3]=1;
                    tuple[i*3+1][j*3+1]=1;
                    tuple[i*3+2][j*3+2]=1;
                }
            }
        }
        //BFS求連通量
        int count=0;
        for (int i = 0; i <  tupleL; i++) {
            for (int j = 0; j < tupleL; j++) {
                    if(tuple[i][j]==0){
                        //輔助佇列
                        Queue<Integer> queue = new LinkedList<>();
                        //將二維座標轉換成一維
                        queue.add(i*tupleL+j);
                        tuple[i][j]=1;
                        count++;
                        while (!queue.isEmpty()){
                            //獲取二維座標
                            int index=queue.remove();
                            int row=index/tupleL;
                            int col=index%tupleL;
                            //上下左右廣度搜索
                            if(row-1>=0&&tuple[row-1][col]==0){
                                queue.add((row-1)*tupleL+col);
                                tuple[row-1][col]=1;
                            }
                            if(row+1<tupleL&&tuple[row+1][col]==0){
                                queue.add((row+1)*tupleL+col);
                                tuple[row+1][col]=1;
                            }
                            if(col-1>=0&&tuple[row][col-1]==0){
                                queue.add(row*tupleL+col-1);
                                tuple[row][col-1]=1;
                            }
                            if(col+1<tupleL&&tuple[row][col+1]==0){
                                queue.add(row*tupleL+col+1);
                                tuple[row][col+1]=1;
                            }
                        }
                    }
            }
        }
        return count;
    }

}