由斜杠划分区域--并查集

LeetCode 559

由斜杠划分区域

在由 1 x 1 方格组成的 N x N 网格 grid 中,每个 1 x 1 方块由 /、\ 或空格构成。这些字符会将方块划分为一些共边的区域。

(请注意,反斜杠字符是转义的,因此 \ 用 “\” 表示。)。

返回区域的数目。

示例1:

输入:
[
  " /",
  "/ "
]
输出:2
解释:2x2 网格如下:

示例2:

输入:
[
  "\\/",
  "/\\"
]
输出:4
解释:(回想一下,因为 \ 字符是转义的,所以 "\\/" 表示 \/,而 "/\\" 表示 /\。)

解法:并查集

解题思路:

这道题可以用并查集的思想来解决,不了解并查集的可以看这篇博客并查集,通过并查集,我们来判断是否存在环,如果存在一个环,那该区域能被划分的个数就要加1,现在的问题是如何把二维数组变成一个图

我们可以把每一个方块分为四个顶点,这样,我们就能得到边了

代码如下:

class Solution
{
    /**
    * 思路: Disjointed Set, 并查集
    * 对每一个点进行标注, [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
    * 之后,根据点的标注建立无向图
    * 利用并查集查找环
    * 添加一条边,若存在以当前边终点为闭合点的环,则将当前区域划分为两个区域,结果加 1
    */
    public int regionsBySlashes(String[] grid) 
    {
        int row = grid.length+1; 
        int col = grid[0].length()+1;
        int res = 1;
        int[] parents = new int[row * col]; 
        // 初始化父节点数组, 尽量均匀分布
        for (int i=0; i<row*col; i++) 
        {
            parents[i] = -1;
        }
        // 首先需要添加正方形的边线, 正方形本身就成环
        for (int i=0; i<col; i++) //上下两水平线差为col*(row-1)
        {
            parents[i] = i-1;
            parents[col*(row-1)+i] = col*(row-1)+i-1;
        }
        for (int i=1; i<row; i++) //左右两竖直线差为1个col-1
        {
            parents[col*i] = col*(i-1);
            parents[col*(i+1)-1] = col*i-1;
        }

        // 每遇到一条边,更新根节点,判断是否成环
        for (int i=0; i<row-1; i++) 
        {
            for (int j=0; j<col-1; j++) 
            {
                if (grid[i].charAt(j) == '/') 
                {
                    res += isRing(i * col + j+1, (i+1)*col+j, parents);
                } 
                else if (grid[i].charAt(j) == '\\') 
                {
                    res += isRing(i*col+j, (i+1)*col+j+1, parents);
                }
            }
        }
        return res;
    }

    public int isRing(int a, int b, int[] parents) {
        // 如果 对应点 均存在父节点,则判断其根节点是否相同,相同则成环,返回 1; 否则,合并两根节点,并返回 0
        // 如果一个点存在父节点,另一个点不存在父节点,则更新不存在父节点的点的父节点
        // 如果两个点都不存在父节点(均为根节点),则合并两个根节点
        if (parents[a] > -1 && parents[b] > -1) //如果两个结点都不是根结点
        {
            int rootA = parents[a];
            int rootB = parents[b];
            while (parents[rootA] > -1) //找根结点
            {
                rootA = parents[rootA];
            }
            while (parents[rootB] > -1) 
            {
                rootB = parents[rootB];
            }
            if (rootA==rootB) 
            { // 根节点相同,成环,返回 1
                return 1;
            } 
            else 
            {            // 根节点不同,不成环,合并两个根节点,并返回 0
                if (rootA < rootB) 
                {    // 此处偷懒,强制 序号 更大的根节点 合并到 序号 较小的根节点上
                    parents[rootB] = rootA;
                } 
                else 
                {
                    parents[rootA] = rootB;
                }
                return 0;
            }
        } 
        else if (parents[a] > -1) 
        {   // 给图添加新边
            parents[b] = a;
        } 
        else if (parents[b] > -1) 
        {
            parents[a] = b;
        } 
        else 
        {
            parents[b] = a;
        }
        return 0;
    }
}

这里并没有进行路径压缩

解法来源

作者:HuaJiuShi

链接:https://leetcode-cn.com/problems/regions-cut-by-slashes/solution/xian-yong-tu-xiang-chu-li-de-sao-cao-zuo-miao-liao/
来源:力扣(LeetCode)

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值