广度优先搜索 BFS 专题 (II):Leetcode 130 被围绕的区域 + Leetcode 200 岛屿数量

广度优先搜索 BFS 专题 (II):Leetcode 130 被围绕的区域 + Leetcode 200 岛屿数量

广度优先搜索的主要思想是:将目前所能发现的节点(位置)记录进栈,并随着时间推移,对这些点进行一一检索,达到一个遍历该联通集合中的所有节点的目的。

Leetcode 130 被围绕的区域

来源:https://leetcode-cn.com/problems/surrounded-regions/

题目描述

给定一个二维的矩阵,包含 ‘X’ 和 ‘O’(字母 O)。找到所有被 ‘X’ 围绕的区域,并将这些区域里所有的 ‘O’ 用 ‘X’ 填充。

示例:

X X X X
X O O X
X X O X
X O X X
运行你的函数后,矩阵变为:
X X X X
X X X X
X X X X
X O X X

解释: 被围绕的区间不会存在于边界上,换句话说,任何边界上的 ‘O’ 都不会被填充为 ‘X’。 任何不在边界上,或不与边界上的 ‘O’ 相连的 ‘O’ 最终都会被填充为 ‘X’。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。

题解

思路分为几步:

  1. 初始化:将边界上所有的 “O” 放入栈中。
  2. 搜索可行点:从外部向内搜寻所有与 “O” 相邻的 “O” 。
  3. 广度优先扩展:并将所有通过搜索可行点找到的 “O” ,都标记为 “-” ,以标识为这个点是否已经被发现了。
  4. 终结技:等所有可被发现的点都变为 “-” 后(也就是栈空),将所有 “-” 标记为 “O” 将所有 “O” 标记为 “X”。,得到最终结果。

代码如下:

class Solution(object):
    def solve(self, board):
        def around(m, n, O):
            aroundO = []
            if O[0] < m-1:
                aroundO.append((O[0]+1, O[1]))
            if O[0] > 0:
                aroundO.append((O[0]-1, O[1]))
            if O[1] > 0:
                aroundO.append((O[0], O[1]-1))
            if O[1] < n-1:
                aroundO.append((O[0], O[1]+1))
            return aroundO
        if not board: return None
        if (len(board[0]) == 1) or (len(board) == 1): return None
        m = len(board)
        n = len(board[0])
        Os = []
        for i in range(n):
            if board[0][i] == "O": 
                board[0][i] = "-"
                Os.append((0, i))
            if board[-1][i] == "O": 
                board[-1][i] = "-"
                Os.append((m - 1, i))
        for i in range(1, m-1):
            if board[i][0] == "O": 
                board[i][0] = "-"
                Os.append((i, 0))
            if board[i][-1] == "O": 
                board[i][-1] = "-"
                Os.append((i, n - 1))
        while Os:
            O = Os.pop()
            srd = around(m, n, O)
            for pos in srd:
                if board[pos[0]][pos[1]] == "O":
                    board[pos[0]][pos[1]] = "-"
                    Os.append((pos[0], pos[1]))
        for i in range(m):
            for j in range(n):
                if board[i][j] == "O":
                    board[i][j] = "X"
                elif board[i][j] == "-":
                    board[i][j] = "O"

执行结果

执行用时:48 ms

内存消耗:15.6 MB

在这里插入图片描述

Leetcode 200 岛屿数量

来源:https://leetcode-cn.com/problems/number-of-islands/

题目描述

给定一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。

示例:

输入:
11110
11010
11000
00000	
输出: 1

输入:
11000
11000
00100
00011	
输出: 3

题解:

这个问题实际上就是寻找这个图中有多少不连通的子图。我们只需要找一个点,遍历一遍。栈空的时候,计数,再看看是否还有别的节点没被访问道(标记为1的节点位置),如果有,就重新放到栈里;没有则结束,返回有几块。

代码如下:

class Solution(object):
    def numIslands(self, grid):
        def around(m, n, O):
            aroundO = []
            if O[0] < m-1:
                aroundO.append((O[0]+1, O[1]))
            if O[0] > 0:
                aroundO.append((O[0]-1, O[1]))
            if O[1] > 0:
                aroundO.append((O[0], O[1]-1))
            if O[1] < n-1:
                aroundO.append((O[0], O[1]+1))
            return aroundO
        def SearchFor1(m, n, grid):
            for i in range(m):
                for j in range(n):
                    if grid[i][j] == "1":
                        return (i, j)
            return None
        if not grid: return 0
        m, n = len(grid), len(grid[0])
        pos = SearchFor1(m, n, grid)
        if not pos:
            return 0
        lst, count = [pos], 1
        while lst:
            pos = lst.pop(0)
            grid[pos[0]][pos[1]] = "-"
            sur = around(m, n, pos)
            for p in sur:
                if grid[p[0]][p[1]] == "1":
                    grid[p[0]][p[1]] = "-"
                    lst.append((p[0], p[1]))
            if not lst:
                temp = SearchFor1(m, n, grid)
                if not temp:
                    return count
                else:
                    lst = [temp]
                    count += 1
        return count

执行结果

执行时间:316 ms

内存消耗:15.1 MB

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值