算法练习帖--56--由斜杠划分区域(Java)

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

}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值