leetcode刷题日记———深度优先搜索(岛屿问题)

岛屿数量

题目描述:给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。
输入:
11000
11000
00100
00011
输出: 3
解释: 每座岛屿只能由水平和/或竖直方向上相邻的陆地连接而成

基本思路:深度优先搜索,遍历矩阵中所有为1的网格,然后dfs,这里将访问过的节点做标记,防止再次访问。

代码如下:

class Solution:
    directions = [(-1,0),(0,1),(1,0),(0,-1)]
    def numIslands(self, grid: List[List[str]]) -> int:
        m = len(grid)
        if m==0:return 0
        n = len(grid[0])

        marked = [[False for _ in range(n)]for _ in range(m)]
        count = 0
        for i in range(m):
            for j in range(n):
                if not marked[i][j] and grid[i][j]=="1":
                    self.dfs(grid,i,j,m,n,marked)
                    count += 1
        return count

    def dfs(self,grid,i,j,m,n,marked):
        marked[i][j]=True
        for direction in self.directions:
            new_i = i+ direction[0]
            new_j = j+ direction[1]
            if 0<=new_i<m and 0<=new_j<n and not marked[new_i][new_j] and grid[new_i][new_j]=="1":
                self.dfs(grid,new_i,new_j,m,n,marked)

岛屿的最大面积

题目描述:给定一个包含了一些 0 和 1 的非空二维数组 grid 。

一个 岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在水平或者竖直方向上相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。

找到给定的二维数组中最大的岛屿面积。(如果没有岛屿,则返回面积为 0 。)

基本思路:深度优先搜索,遍历每个岛屿,遇到1就将面积++,且将此位置标记,防止再次被访问。
代码如下:、

class Solution:
    def dfs(self, grid, cur_i, cur_j):
        if cur_i < 0 or cur_j < 0 or cur_i == len(grid) or cur_j == len(grid[0]) or grid[cur_i][cur_j] != 1:
            return 0
        grid[cur_i][cur_j] = 0
        ans = 1
        for di, dj in [[0, 1], [0, -1], [1, 0], [-1, 0]]:
            next_i, next_j = cur_i + di, cur_j + dj
            ans += self.dfs(grid, next_i, next_j)
        return ans

    def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
        ans = 0
        for i, l in enumerate(grid):
            for j, n in enumerate(l):
                if grid[i][j]==1:
                    ans = max(self.dfs(grid, i, j), ans)
        return ans

岛屿周长

题目描述:给定一个包含 0 和 1 的二维网格地图,其中 1 表示陆地 0 表示水域。

网格中的格子水平和垂直方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有一个岛屿(或者说,一个或多个表示陆地的格子相连组成的岛屿)。

岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连)。格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100 。计算这个岛屿的周长。

基本思路:直接遍历数组,如果当前位置为1,然后查看其上下左右四个方向的位置,如果不在矩阵中或者为0,就将周长加1.

class Solution:
    def islandPerimeter(self, grid: List[List[int]]) -> int:
        dir = [[1,0],[0,1],[-1,0],[0,1]]
        perimeter = 0
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j]==1:
                    for v in dir:
                        idx, idy = i+v[0], j+v[1]
                        if idx<0 or idx>=len(grid) or idy<0 or idy>=len(grid[0]):
                            perimeter += 1
                        else:
                            if grid[idx][idy]==0:perimeter+=1
        return perimeter在这里插入代码片

统计封闭岛屿的数目

题目描述:有一个二维矩阵 grid ,每个位置要么是陆地(记号为 0 )要么是水域(记号为 1 )。

我们从一块陆地出发,每次可以往上下左右 4 个方向相邻区域走,能走到的所有陆地区域,我们将其称为一座「岛屿」。

如果一座岛屿 完全 由水域包围,即陆地边缘上下左右所有相邻区域都是水域,那么我们将其称为 「封闭岛屿」。

请返回封闭岛屿的数目。

基本思路:这里与之前不同的是,要求返回的是封闭岛屿的数量,封闭岛屿是岛屿上每个点都不在边界上,所以这里我们在dfs中判断岛屿是否有点在边界上。

代码如下:

class Solution:
    def closedIsland(self, grid: List[List[int]]) -> int:
        m, n = len(grid), len(grid[0])
        count = 0
        for i in range(m):
            for j in range(n):
                if grid[i][j]==0:
                    if not self.dfs(grid,i,j,m,n):count += 1
        return count

    def dfs(self,grid,i,j,m,n):
        if i<0 or i==m or j<0 or j==n:
            return True
        if grid[i][j]!=0:
            return False
        grid[i][j] = 2
        dir1 = self.dfs(grid,i+1,j,m,n)
        dir2 = self.dfs(grid,i,j+1,m,n)
        dir3 = self.dfs(grid,i-1,j,m,n)
        dir4 = self.dfs(grid,i,j-1,m,n)
        return dir1 or dir2 or dir3 or dir4

最大人工岛

题目描述:在二维地图上, 0代表海洋, 1代表陆地,我们最多只能将一格 0 海洋变成 1变成陆地。

进行填海之后,地图上最大的岛屿面积是多少?(上、下、左、右四个方向相连的 1 可形成岛屿)

基本思路:(1)我们依次将地图中海洋的位置变成陆地,然后在这张地图上寻找岛屿面积最大的
(2)用dfs遍历一遍地图,记录每个岛屿的面积,不同的岛屿用不同的标记,且记录该标记对应岛屿的面积。
在遍历一遍地图,对于海洋的位置,寻找其上下左右四个方向的不同岛屿将其面积相加,其中海洋可以看做面积为0的岛屿。

代码如下:

class Solution:
    def largestIsland(self, grid: List[List[int]]) -> int:
        ans = 0 
        maxv = 0
        color = 2
        dict = {}
        dict[0]=0
        for i, l in enumerate(grid):
            for j, n in enumerate(l):
                if grid[i][j]==1:
                    ans = self.dfs(grid, i, j,color)
                    maxv = max(ans,maxv)
                dict[color] = ans
                ans = 0
                color += 1
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j]==0:
                    count = 0
                    p =set()
                    for v in [[0, 1], [0, -1], [1, 0], [-1, 0]]:
                        around_i, around_j = i+v[0], j+v[1]
                        if 0<=around_i<len(grid) and 0<=around_j<len(grid[0]):
                            p.add(grid[around_i][around_j])
                    for k in p:
                        count += dict[k]
                    maxv = max(count + 1, maxv)                     
        return maxv
    def dfs(self, grid, cur_i, cur_j,color):
        if cur_i < 0 or cur_j < 0 or cur_i == len(grid) or cur_j == len(grid[0]) or grid[cur_i][cur_j] != 1:
            return 0
        grid[cur_i][cur_j] = color
        ans = 1
        for di, dj in [[0, 1], [0, -1], [1, 0], [-1, 0]]:
            next_i, next_j = cur_i + di, cur_j + dj
            ans += self.dfs(grid, next_i, next_j,color)
        return ans

        

被围绕的区域

给定一个二维的矩阵,包含 ‘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’。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。

基本思路:被围绕的区域为“O”且不与其他在边界上的“O”相连,反过来,我们先找到在边界的“O”,然后将其及与它相邻的“O”做标记“A”,然后遍历矩阵将剩下的“O”替换成“X”,再遍历矩阵将“A”替换会“O”

class Solution:
    def dfs(self,board,i,j,m,n):
            if i<0 or i==m or j<0 or j==n:
                return 
            if board[i][j]!="O":
                return
            board[i][j]="A"
            dir1 = self.dfs(board,i+1,j,m,n)
            dir2 = self.dfs(board,i,j+1,m,n)
            dir3 = self.dfs(board,i-1,j,m,n)
            dir4 = self.dfs(board,i,j-1,m,n)
            return dir1 or dir2 or dir3 or dir4
    def solve(self, board: List[List[str]]) -> None:
        """
        Do not return anything, modify board in-place instead.
        """
        if not board:return board
        m, n = len(board), len(board[0])
        for i in range(m):
            for j in range(n):
                if board[i][j]=="O" and (i==0 or i==m-1 or j==0 or j==n-1):
                    self.dfs(board,i,j,m,n)
        for i in range(m):
            for j in range(n):
                if board[i][j]=="O":board[i][j]="X"
        for i in range(m):
            for j in range(n):
                if board[i][j]=="A":board[i][j]="O"
        
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值