[LeetCode解题报告] 959. 由斜杠划分区域

一、 题目

1. 题目描述

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

给定网格 grid 表示为一个字符串数组,返回 区域的数量

请注意,反斜杠字符是转义的,因此 '\''\\' 表示。

 

    示例 1:

    输入:grid = [" /“,”/ "]
    输出:2

    示例 2:

    输入:grid = [" /“,” "]
    输出:1

    示例 3:

    输入:grid = [“/\”,“\/”]
    输出:5
    解释:回想一下,因为 \ 字符是转义的,所以 “/\” 表示 /\,而 “\/” 表示 /。

     

    提示:

    • n == grid.length == grid[i].length
    • 1 <= n <= 30
    • grid[i][j] 是 '/''\'、或 ' '
    Related Topics
    • 深度优先搜索
    • 广度优先搜索
    • 并查集

    • 👍 305
    • 👎 0

    2. 原题链接

    链接: 959. 由斜杠划分区域

    二、 解题报告

    1. 思路分析

    方法一、并查集
    1. 把每条边加入并查集,那么空格代表四个边可连通,/代表上边左边通、右边下边通,同理\代表左下通、右上通
    2. 最后计数祖宗节点即可
    方法二、DFS连通分量
    1. 把每个格子扩展成3×3的格子,计算连通分量即可。

    2. 复杂度分析

    每个格子只会计算一次,因此两种的复杂度都是O(n2)

    3.代码实现

    并查集

    class Solution:
        def regionsBySlashes(self, grid: List[str]) -> int:
            n = len(grid)
            # (x,y,0) 左端点代表一个横边,tag0
            # (x,y,1) 用上端点代表一个竖边,tag1
            def top(i,j):  # 正方形i,j的顶边
                return (i,j,0)
            def bottom(i,j):  # 低边
                return (i+1,j,0)
            def left(i,j):  # 左边
                return (i,j,1)
            def right(i,j):  # 右边
                return (i,j+1,1)
            fathers = {}
            # 初始化,把所有边加入并查集
            for i in range(n):
                for j in range(n):
                    fathers[top(i,j)] = top(i,j)
                    fathers[left(i,j)] = left(i,j) 
            for i in range(n):
                    fathers[right(i,n-1)] = right(i,n-1)
                    fathers[bottom(n-1,i)] = bottom(n-1,i)
                
            def find_father(x):
                if fathers[x] != x:
                    fathers[x] = find_father(fathers[x])
                return fathers[x]          
            def union(x,y):
                x = find_father(x)
                y = find_father(y)
                fathers[x] = y      
            
            for i in range(n):
                for j in range(n):
                    if grid[i][j] == ' ':  # 四个边都连起来
                        union(top(i,j),bottom(i,j))
                        union(top(i,j),left(i,j))
                        union(top(i,j),right(i,j))
                    elif grid[i][j] == '/':  # 上左连,下右连
                        union(top(i,j),left(i,j))
                        union(bottom(i,j),right(i,j))
                    else:  # 上右连,下左连
                        union(top(i,j),right(i,j))
                        union(bottom(i,j),left(i,j))
            ans = set([find_father(x) for x in fathers ])
            # print(fathers)
            # print(ans)
            return len(ans)
    

    DFS

    class Solution:
        def regionsBySlashes(self, grid: List[str]) -> int:
            n = len(grid)
            m = 3*n
            # 把每个小格子转化成3*3的格子,求连通分量
            new_grid = [[0]*m for _ in range(m)]
            for i in range(n):
                for j in range(n):
                    if grid[i][j] == ' ': 
                       pass
                    elif grid[i][j] == '/':  
                        new_grid[i*3][j*3+2] = 1
                        new_grid[i*3+1][j*3+1] = 1
                        new_grid[i*3+2][j*3] = 1
                    else:  
                        new_grid[i*3][j*3] = 1
                        new_grid[i*3+1][j*3+1] = 1
                        new_grid[i*3+2][j*3+2] = 1
            
            def dfs(x,y):
                if 0 <= x < m and 0 <= y < m and new_grid[x][y] == 0:
                    new_grid[x][y] = 1                
                    dfs(x+1,y)
                    dfs(x-1,y)
                    dfs(x,y+1)
                    dfs(x,y-1)            
                              
            ans = 0
            for i in range(m):
                for j in range(m):
                    if new_grid[i][j] == 0:
                        ans += 1
                        dfs(i,j)
            return ans
    

    三、 本题小结

    1. 计算连通分量,需要一点技巧。我一开始想到的是并查集。
    • 0
      点赞
    • 0
      收藏
      觉得还不错? 一键收藏
    • 0
      评论
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值