695. 岛屿的最大面积

先上最经典的题目,详细思路看这题的官方题解,简单来说的岛屿问题就是遍历二维数组,一般都是从一块陆地开始,进行深度优先或者广度优先搜索,每次上下左右四个方向选其一然后寻找下一块陆地,最后找到一整个岛屿(一片陆地)。

广度优先搜索:

class Solution:def maxAreaOfIsland(self, grid: List[List[int]]) -> int:ans = 0nr = len(grid)if nr == 0:return 0nc = len(grid[0])for r in range(nr):for c in range(nc):if grid[r][c] == 1:queue = collections.deque([(r, c)]) # 队列grid[r][c] = 2cur = 1while queue:row, col = queue.popleft() # 先进先出for x, y in [(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]:if 0 <= x < nr and 0 <= y < nc and grid[x][y] == 1:cur += 1queue.append((x, y))grid[x][y] = 2ans = max(ans, cur)return ans

nr是行的长度,nc是列的长度,遍历整个二维数组,如果遇到陆地if grid[r][c] == 1就开始找岛屿。广度优先搜索用的是队列,记录的是二维坐标。grid[r][c] = 2的目的是防止重复遍历。cur是当前岛屿的面积。从一块陆地出发,如果它的四个方向[(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]的下一个坐标(x, y)在范围内并且为陆地的话,就把它加入队列中,同时标记已遍历,cur也加1。ans记录最大的岛屿面积。

深度优先搜索:

class Solution:def maxAreaOfIsland(self, grid: List[List[int]]) -> int:ans = 0nr = len(grid)if nr == 0:return 0nc = len(grid[0])for r in range(nr):for c in range(nc):if grid[r][c] == 1:stack = [(r, c)] # 栈grid[r][c] = 2cur = 1while stack:row, col = stack.pop() # 先进后出for x, y in [(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]:if 0 <= x < nr and 0 <= y < nc and grid[x][y] == 1:cur += 1stack.append((x, y))grid[x][y] = 2ans = max(ans, cur)return ans

深度优先搜索和广度优先搜索基本一样,只是改用来实现,每次弹出的位置就是刚刚加入的,即一条路走到底,再往回走(深度);广度优先则按顺序弹出,一定把最初的位置遍历完之后再遍历新的,如同石头落入水中产生涟漪(广度)。

广度优先与深度优先切换,只需要改一条初始化语句,一个pop函数,几个变量名就行了。

200. 岛屿数量

广度优先搜索:

class Solution:def numIslands(self, grid: List[List[str]]) -> int:ans = 0nr = len(grid)if nr == 0:return 0nc = len(grid[0])for r in range(nr):for c in range(nc):if grid[r][c] == "1":queue = collections.deque([(r, c)])grid[r][c] = "2"ans += 1while queue:row, col = queue.popleft()for x, y in [(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]:if 0 <= x < nr and 0 <= y < nc and grid[x][y] == "1":queue.append((x, y))grid[x][y] = "2"return ans

深度优先搜索:

class Solution:def numIslands(self, grid: List[List[str]]) -> int:ans = 0nr = len(grid)if nr == 0:return 0nc = len(grid[0])for r in range(nr):for c in range(nc):if grid[r][c] == "1":stack = [(r, c)]grid[r][c] = "2"ans += 1while stack:row, col = stack.pop()for x, y in [(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]:if 0 <= x < nr and 0 <= y < nc and grid[x][y] == "1":stack.append((x, y))grid[x][y] = "2"return ans

代码框架基本相同,区别:这题的数字用字符来表示,是“1”而不是1;不需要记录当前岛屿的面积,只需要在进入一块新陆地找岛屿时ans加1即可,实际上比上一题简单。

694. 不同岛屿的数量

广度优先搜索:

class Solution:def numDistinctIslands(self, grid: List[List[int]]) -> int:ans = set()nr = len(grid)if nr == 0:return 0nc = len(grid[0])for r in range(nr):for c in range(nc):if grid[r][c] == 1:queue = collections.deque([(r, c)])grid[r][c] = 2path = 'a'while queue:row, col = queue.popleft()nxt = [(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]for i in range(4): # 为了记录方向x, y = nxt[i]if 0 <= x < nr and 0 <= y < nc and grid[x][y] == 1:path += str(i)queue.append((x, y))grid[x][y] = 2path += 'a'ans.add(path)return len(ans)

深度优先搜索:

class Solution:def numDistinctIslands(self, grid: List[List[int]]) -> int:ans = set()nr = len(grid)if nr == 0:return 0nc = len(grid[0])for r in range(nr):for c in range(nc):if grid[r][c] == 1:stack = [(r, c)]grid[r][c] = 2path = 'a'while stack:row, col = stack.pop()nxt = [(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]for i in range(4): # 为了记录方向x, y = nxt[i]if 0 <= x < nr and 0 <= y < nc and grid[x][y] == 1:path += str(i)stack.append((x, y))grid[x][y] = 2path += 'a'ans.add(path)return len(ans)

这题找的是不同岛屿的数量,如何定义岛屿是否相同(模式)呢?题目说明:两个岛屿被认为是相同的,当且仅当一个岛屿可以通过平移变换(不可以旋转、翻转)和另一个岛屿重合。由于我们找陆地时是从左上向右下找的,所以进入某种形状岛屿的位置是确定的,因此,可以用探索岛屿的路径(方向组合)来表示这个岛屿(类似动作游戏的上下左右组合技能)。

具体方法就是用字符串记录这个方向的组合,同时要避免不同形状的岛屿出现相同路径的情况,在每次遍历时加入标记path += 'a',保证路径的唯一性。

463. 岛屿的周长

广度优先搜索:

class Solution:def islandPerimeter(self, grid: List[List[int]]) -> int:ans = 0nr = len(grid)if nr == 0:return 0nc = len(grid[0])for r in range(nr):for c in range(nc):if grid[r][c] == 1:stack = [(r, c)]grid[r][c] = 2while stack:row, col = stack.pop()for x, y in [(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]:if (x < 0 or x >= nr or y < 0 or y >= nc) or (0 <= x < nr and 0 <= y < nc and grid[x][y] == 0):ans += 1if 0 <= x < nr and 0 <= y < nc and grid[x][y] == 1:stack.append((x, y))grid[x][y] = 2return ans

深度优先搜索:

class Solution:def islandPerimeter(self, grid: List[List[int]]) -> int:ans = 0nr = len(grid)if nr == 0:return 0nc = len(grid[0])for r in range(nr):for c in range(nc):if grid[r][c] == 1:stack = [(r, c)]grid[r][c] = 2while stack:row, col = stack.pop()for x, y in [(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]:if (x < 0 or x >= nr or y < 0 or y >= nc) or (0 <= x < nr and 0 <= y < nc and grid[x][y] == 0):ans += 1if 0 <= x < nr and 0 <= y < nc and grid[x][y] == 1:stack.append((x, y))grid[x][y] = 2return ans

本题中只有一个岛屿,注意周长即岛屿的边界,只会出现在陆地与大边界或者海洋的交界处,即指向四个方向的下一个坐标(x,y)有 if (x < 0 or x >= nr or y < 0 or y >= nc) or (0 <= x < nr and 0 <= y < nc and grid[x][y] == 0):越界或者是海洋。

827. 最大人工岛

广度优先搜索:

class Solution:def largestIsland(self, grid: List[List[int]]) -> int:ans = 0nr = len(grid)if nr == 0:return 0nc = len(grid[0])area = {}index = 2for r in range(nr):for c in range(nc):if grid[r][c] == 1:queue = collections.deque([(r, c)]) # 队列grid[r][c] = indexcur = 1while queue:row, col = queue.popleft() # 先进先出for x, y in [(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]:if 0 <= x < nr and 0 <= y < nc and grid[x][y] == 1:cur += 1queue.append((x, y))grid[x][y] = indexarea[index] = curindex += 1ans = max(area.values() or [0])for r in range(nr):for c in range(nc):if grid[r][c] == 0:seen = set()for x, y in [(r - 1, c), (r + 1, c), (r, c - 1), (r, c + 1)]:if 0 <= x < nr and 0 <= y < nc and grid[x][y] > 1:seen.add(grid[x][y])ans = max(ans, 1 + sum(area[i] for i in seen))return ans

深度优先搜索:

class Solution:def largestIsland(self, grid: List[List[int]]) -> int:ans = 0nr = len(grid)if nr == 0:return 0nc = len(grid[0])area = {}index = 2for r in range(nr):for c in range(nc):if grid[r][c] == 1:stack = [(r, c)] # 队列grid[r][c] = indexcur = 1while stack:row, col = stack.pop() # 先进先出for x, y in [(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]:if 0 <= x < nr and 0 <= y < nc and grid[x][y] == 1:cur += 1stack.append((x, y))grid[x][y] = indexarea[index] = curindex += 1ans = max(area.values() or [0]) # 防止全1的情况for r in range(nr):for c in range(nc):if grid[r][c] == 0:seen = set()for x, y in [(r - 1, c), (r + 1, c), (r, c - 1), (r, c + 1)]:if 0 <= x < nr and 0 <= y < nc and grid[x][y] > 1:seen.add(grid[x][y])ans = max(ans, 1 + sum(area[i] for i in seen))return ans

一道困难题,基本思路是将现有的岛屿遍历一次,用字典标记不同的岛屿和岛屿面积,然后再遍历所有的海洋格子,填充该格子后的大岛屿面积就是这个格子四个方向的任两个岛屿面积之和加1,找出最大值即可。

1034. 边界着色

递归法:

class Solution:def colorBorder(self, grid: List[List[int]], row: int, col: int, color: int) -> List[List[int]]:m, n = len(grid), len(grid[0])explored = set()def dfs(r, c):# 当前是遍历过的连通分量if (r, c) in explored:return False# 当前越界了,说明上一次的在网格的边界上if r < 0 or c < 0 or r == m or c == n:return True# 当前不是连通分量,说明上一次的与不在分量中的网格相邻if grid[r][c] != grid[row][col]:return True# 当前的是范围内的没遍历过的连通分量explored.add((r,c))isBorder = Falsefor dx, dy in (0,1),(1,0),(0,-1),(-1,0):if dfs(r+dx, c+dy):isBorder = Trueif isBorder:grid[r][c] = colorreturn Falsedfs(row, col)return grid

迭代法:

class Solution:def colorBorder(self, grid: List[List[int]], row: int, col: int, color: int) -> List[List[int]]:m, n = len(grid), len(grid[0])explored = set()original_color = grid[row][col]stack = [(row, col)]while stack:r, c = stack.pop()explored.add((r,c))for dx, dy in (0,1),(1,0),(0,-1),(-1,0):# 下一步越界了,说明(r,c)在网格的边界上if r+dx < 0 or c+dy < 0 or r+dx == m or c+dy == n:grid[r][c] = color# 遍历过的连通分量跳过elif (r+dx, c+dy) in explored:continue# 下一步不是连通分量,说明(r,c)与不在分量中的网格相邻elif grid[r+dx][c+dy] != original_color:grid[r][c] = colorelse:stack.append((r+dx, c+dy))return grid

这题指定了遍历的起点 (row, col),所以迭代法实现中就不能用 for 循环而要用 while 循环。从起点出发,记录下遍历过的节点,然后考察其四个方向的下一个节点:如果下一个的节点越界了,说明当前节点在边界上,则需要着色;如果下一个节点是遍历过的连通分量,则跳过;如果下一个节点不是连通分量,则需要着色;剩下的情况就是下一个节点是在边界内的、为遍历过的连通分量,则加入栈。

1765. 地图中的最高点

class Solution:def highestPeak(self, isWater: List[List[int]]) -> List[List[int]]:m, n = len(isWater), len(isWater[0])ans = [[water-1 for water in row] for row in isWater]q = collections.deque((i, j) for i, row in enumerate(isWater) for j, _ in enumerate(row) if ans[i][j] == 0)while q:i, j = q.popleft()for x, y in ((i+1, j), (i-1, j), (i, j+1), (i, j-1)):if 0 <= x < m and 0 <= y < n and ans[x][y] == -1:ans[x][y] = ans[i][j] + 1q.append((x, y))return ans

广度优先遍历,先把所有的 water 方格坐标加入队列作为起始点,然后遍历它们上下左右的格子,如果是还没被遍历过的,就在 ans 中高度加 1 并且加入队列,直到没有格子为止。

岛屿类问题的广度优先深度优先双解法(Leetcode题解-Python语言)相关推荐

  1. 爬楼梯与路径类题目记忆化递归与动态规划双解法(Leetcode题解-Python语言)

    70. 爬楼梯(剑指 Offer 10- II. 青蛙跳台阶问题) 递归(英语:Recursion),是指在函数的定义中使用函数自身的方法.有意义的递归通常会把问题分解成规模缩小的同类子问题,当子问题 ...

  2. 买卖股票类问题动态规划解法(Leetcode题解-Python语言)

    在 Leetcode 中,关于买卖股票的问题共有6道,而这些题目是可以用相同的思维进行求解的,强烈推荐这篇总结,写得非常到位. 股票类问题的动态规划分三步走,1.首先明确方程的含义, T[i][k][ ...

  3. 二叉树层序遍历(广度优先搜索)基础概念与经典题目(Leetcode题解-Python语言)

    二叉树的广度优先搜索即从上到下.从左到右地进行搜索,对于层序遍历(Level Order)问题,即依次遍历第一层节点.第二层节点-等,基本可以秒杀. 广度优先搜索是通过队列来实现的,python中优先 ...

  4. 解决岛屿类问题(网格)通用解法DFS(附题)

    力扣695 class Solution { public:bool check(vector<vector<int>>&grid,int r,int c){retur ...

  5. 岛屿类问题通用解法与DFS框架

    参考链接: https://leetcode.cn/problems/number-of-islands/solution/dao-yu-lei-wen-ti-de-tong-yong-jie-fa- ...

  6. 岛屿类-网格类问题-DFS | 力扣695. 岛屿的最大面积

    思路参考上文: 岛屿类-网格类问题-DFS | 力扣200. 岛屿数量 本文讲解695. 岛屿的最大面积问题,属于常见的岛屿类-网格类问题 本题使用DFS的思想 题目 给定一个包含了一些 0 和 1 ...

  7. 岛屿类-网格类问题-DFS | 力扣200. 岛屿数量

    本文讲解200. 岛屿数量问题,属于常见的岛屿类-网格类问题 本题使用DFS的思想 1 题目 给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量. 岛屿总是被水包围, ...

  8. 第十二周项目五-----迷宫问题之图深度优先遍历解法

     烟台大学计算机与控制工程学院 作者:孙潇 时间:2015年12月15日 问题描述:[项目 - 迷宫问题之图深度优先遍历解法]   设计一个程序,采用深度优先遍历算法的思路,解决迷宫问题.   ( ...

  9. leetcode岛屿类问题

    岛屿类问题 问题基础 如何在二维矩阵中使用 DFS 搜索呢?如果你把二维矩阵中的每一个位置看做一个节点,这个节点的上下左右四个位置就是相邻节点,那么整个矩阵就可以抽象成一幅网状的「图」结构. 根据二叉 ...

最新文章

  1. Java语言基础22--访问权限
  2. python 求系数矩阵,关于numpy:python-如何在数据矩阵中使用nans计算相关矩阵
  3. IDS与IPS的区别(HIDS、NIDS)
  4. vue加跨域代理静态文件404_解决vue-router history模式和跨域代理 部署到IIS时404的一些问题...
  5. Linux 搭建PHP环境
  6. 对于vertical-align的学习
  7. 易用性强的数据库管理工具DBeaverEE v22.0.1
  8. Hex Editor Neo(十六进制编辑器)官方正式版V6.54.1.6478 | 二进制编辑器hex下载 | 非hexeditor汉化版
  9. 汉字区位码转换为“汉字ASCII码“
  10. Docker设置端口映射
  11. 注册表怎么用计算机管理打开,如何打开注册表,详细教您如何打开电脑注册表管理器...
  12. C语言热电阻温度查表,热电阻分度表如何看?是什么意思?
  13. fprintf函数matlab,fprintf函数的运用(组图)
  14. Wonderful Coloring - 2
  15. Java里面的Lambda表达式
  16. 电加热炉温度控制系统的研究与设计
  17. 用shader做一个柿子颜色的过场动画
  18. python IO模块【一】:IO类
  19. android 怎么刷新view,android – 如何在ViewPager中刷新当前视图
  20. yum-utils与yum-config-manager

热门文章

  1. 值得推荐的微软技术公众号推荐
  2. [转]Android studio 快速解决Gradle's dependency cache may be corrupt 和 Gradle配置 gradle
  3. 【专升本计算机】甘肃省专升本计算机基础--判断题--汇编(737道带答案)
  4. linux之uniq命令
  5. IOS学习笔记二十三对象归档(NSKeyedArchiver、NSKeyedUnArchiver、NSCodeing)
  6. C和指针之字符串总结
  7. C和指针之const、#define、volatile
  8. Andorid之华为手机开发模式不打印日志
  9. Android之URI简介
  10. knex 单表查询_knex.js