当前位置 博文首页 > Inmaturity_7的博客:算法练习帖--56--由斜杠划分区域(Java)

    Inmaturity_7的博客:算法练习帖--56--由斜杠划分区域(Java)

    作者:[db:作者] 时间:2021-07-16 21:53

    由斜杠划分区域(并查集、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]==