岛屿问题通解——网格DFS

岛屿问题通解——网格DFS(深度优先搜索)问题

超赞的总结


200. 岛屿数量

在这里插入图片描述

class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        def dfs(grid, i, j):
            if not 0<=i<len(grid) or not 0<=j<len(grid[0]):  # 或的关系
                return
            if grid[i][j] != '1':
                return
            
            # 当前格子是陆地且未被遍历过
            grid[i][j] = 2  # 2标记该格子已被遍历过
            dfs(grid, i-1, j)
            dfs(grid, i+1, j)
            dfs(grid, i, j+1)
            dfs(grid, i, j-1)

        count = 0
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j] == '1':  # 注意 这里是字符  不是整数
                    dfs(grid, i, j)
                    count += 1
        return count
# grid是可变对象,其在函数内的改变会影响函数外的对象

463. 岛屿的周长

在这里插入图片描述
陆地于海洋的交界处会有一条边长——遇到海洋返回1

class Solution:
    def islandPerimeter(self, grid: List[List[int]]) -> int:
        # 发现规律 遇到一个海洋返回1
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j]==1:
                    return self.dfs(grid, i, j)
    
    def dfs(self, grid, i, j):
        if not 0<=i<len(grid) or not 0<=j<len(grid[0]):  # 超过网格界 及遇到水域
            return 1
        if grid[i][j]==0:  # 遇到水域
            return 1
        if grid[i][j] == 2:  # 当前格子已遍历过  对周长无贡献  不能直接return 否则为None,不能于整数相加
            return 0 

        grid[i][j] = 2  # 对遍历过的格子进行标记
        return self.dfs(grid, i+1, j)+self.dfs(grid,i-1,j)+self.dfs(grid, i, j+1)+self.dfs(grid, i, j-1)

695. 岛屿的最大面积

class Solution:
    def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
        # 在200岛屿数量基础上 还要统计每个岛屿的面积 取最大
        maxArea = 0
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j] == 1:
                    curArea = self.dfs(grid, i, j)
                    maxArea = max(curArea, maxArea)
        return maxArea
    
    def dfs(self, grid, i, j):
        if not 0<=i<len(grid) or not 0<=j<len(grid[0]):
            return 0
        if grid[i][j] != 1:
            return 0

        grid[i][j] = 2
        return 1+ self.dfs(grid, i+1, j)+ self.dfs(grid, i-1, j)+ self.dfs(grid, i, j+1)+ self.dfs(grid, i, j-1)

827. 最大人工岛

分析:
①使用数组记录每个岛屿的序号及面积 若三个岛屿分别为2,3,4(岛屿从2开始编号,避免和陆地1混淆),面积分别为3,5,2,则可使用哈希表{2:3,3:5,4:2}
②先得到每个岛屿的面积,然后遍历网格内的海洋,填当前海洋得到的最大岛屿面积等于1+相邻岛屿的面积(注意不要重复,一个海洋的四边相邻的岛屿可能会是同一个)

class Solution:
    def largestIsland(self, grid: List[List[int]]) -> int:               
        global n
        n = len(grid)

        # 函数——求岛屿面积
        def islandArea(grid, i,j,mark):
            if not 0<=i<n or not 0<=j<n:
                return 0
            if grid[i][j] != 1:  # 已被遍历过或是海洋
                return 0
            
            grid[i][j] = mark  # 对当前岛屿的陆地进行标记
            return 1+islandArea(grid, i+1, j, mark)+islandArea(grid, i-1, j, mark)+islandArea(grid, i, j+1, mark)+islandArea(grid, i, j-1, mark)
        

        # 求人工填海后获得的面积
        def manIslandArea(grid, i, j, hp):
            cover = []  # 记录已遍历过的岛屿
            newarea = 1  # 要加上当前填海的面积
            for ni,nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]: # 向与当前海洋相邻的四个方向找寻岛屿
                if 0<=ni<n and 0<=nj<n and grid[ni][nj] not in cover and grid[ni][nj] in hp:
                    newarea += hp[grid[ni][nj]]
                    cover.append(grid[ni][nj])
            return newarea


        # 遍历岛屿  求出每个岛屿的面积
        hp = {}
        mark = 2  # 岛屿的标记 从2开始
        allland = True
        for i in range(n):
            for j in range(n):
                if grid[i][j] == 1:                                        
                    area = islandArea(grid,i,j,mark)
                    hp[mark] = area
                    mark += 1  # 更新标签

        # 遍历海洋 求出填每个海洋得到的岛屿面积
        curMax = 0
        for i in range(n):
            for j in range(n):
                if grid[i][j] == 0:
                    allland = False
                    manArea = manIslandArea(grid, i, j, hp)
                    curMax = max(manArea, curMax)
        if allland:  # 全为陆地  这种情况要单独讨论 否则输出为0
            return n*n
        return curMax  # 有海洋
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值