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

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 并且加入队列,直到没有格子为止。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307659.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

跟我一起学.NetCore之Options实例演示及分析

前言来啦&#xff01;来啦&#xff01;上一节一堆代码&#xff0c;是不是感觉甚是无味啊&#xff1f;没关系&#xff0c;这里结合上一节内容专注举例演示&#xff0c;绝不废话&#xff01;走起~~~~~正文老规矩&#xff0c;一个WebApi项目走起&#xff0c;项目结构如下&#xff…

leetcode139. 单词拆分

一:题目 二:上码 class Solution { public:/**思路:1.分析题意单词就是物品;字符串就是背包;单词能否组成字符串就是在问,物品能不能将背包装满单词可以重复使用那么说明这是一个完全背包2.动态规划五步走1>:确定dp数组的与下标的含义&#xff08;这里用下标i是由我们的遍历…

二分查找基础概念与经典题目(Leetcode题解-Python语言)二分数值型

二分查找的讲解请见上一篇文章。本文主要记录对数值进行二分的题目解法与思路。 374. 猜数字大小 class Solution:def guessNumber(self, n: int) -> int:left 1right nwhile left < right:mid left (right - left) // 2if guess(mid) 1: # mid < pickleft mi…

大数据下的质量体系建设

一、背景大数据、人工智能是当前也是未来几年IT部门的重点建设方向&#xff0c;新的技术可以为业务突破盈利瓶颈&#xff0c;带来新的增长点&#xff0c;同时我们也发现数据中台也频频在最近的企业财报予以体现&#xff0c;相关的技术岗位需求也是供不应求&#xff0c;与之形成…

Pandas中的 transform() 结合 groupby() 用法示例

首先&#xff0c;假设我们有如下餐厅数据集&#xff1a; import pandas as pddf pd.DataFrame({restaurant_id: [101,102,103,104,105,106,107],address: [A,B,C,D, E, F, G],city: [London,London,London,Oxford,Oxford, Durham, Durham],sales: [10,500,48,12,21,22,14] })…

跟我一起学.NetCore之日志(Log)模型核心

前言鲁迅都说&#xff1a;没有日志的系统不能上线(鲁迅说&#xff1a;这句我没说过&#xff0c;但是在理)&#xff01;日志对于一个系统而言&#xff0c;特别重要&#xff0c;不管是用于事务审计&#xff0c;还是用于系统排错&#xff0c;还是用于安全追踪.....都扮演了很重要的…

Numpy中数组创建函数的辨析

首先推荐Numpy官方的教程&#xff0c;网址。 很多人会对数组创建函数的参数中什么时候要用括号np.zeros((2, 3))&#xff0c;什么时候不用括号np.eye(3, 5)感到疑惑&#xff0c;这里对它们统一进行梳理。&#xff08;按照官方文档的分类方法&#xff09; 1. 一维数组创建函数…

leetcode213. 打家劫舍 II

一:题目 二:上码 class Solution { public:/**思路:1.既然成环了,我们如果选取得一条偷取路径是从头开始得那么我们就不能偷取最后一个,那就不算最后一个偷取一遍2.同理我们也可以不算第一个 偷取一遍计算一次偷取得结果*/int rob(vector<int>& nums) {if(nums.size…

如何使用 C# 中的 ValueTask

在 C# 中利用 ValueTask 避免从异步方法返回 Task 对象时分配翻译自 Joydip Kanjilal 2020年7月6日 的文章 《How to use ValueTask in C#》(https://www.infoworld.com/article/3565433/how-to-use-valuetask-in-csharp.html)异步编程已经使用了相当长一段时间了。近年来&…

一文弄懂Numpy中ndarray的维度(dimension)/轴数(axis/axes)问题

Numpy库的核心是ndarray&#xff0c;实际上就是N维数组&#xff08;N-dimensional array&#xff09;&#xff0c;关于这个数据对象的详细介绍&#xff0c;参考官方文档最为合适。有一点要注意的是&#xff0c;ndarray的内置方法只有30多个&#xff0c;常用的如求平均值可以写a…

leetcode337. 打家劫舍 III

一:题目 二:上码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*…

asp.net core 从 3.1 到 5.0

asp.net core 从 3.1 到 5.0Intro就在前几天&#xff0c;微软宣布了 .NET5 发布了 RC1 版本&#xff0c;这也意味着 .NET5 的开发基本稳定了&#xff0c;正式发布之前&#xff0c;不会再新增新的 Feature&#xff0c;只会专注于修复 BUG 提高稳定性。对于开发者来说&#xff0c…

二叉树的几道相似简单递归题

二叉树中递归的思想&#xff0c;在这本Leetbook中讲的很细了&#xff0c;这里不展开。下面是几道例题&#xff1a; 226. 翻转二叉树&#xff08;剑指 Offer 27. 二叉树的镜像&#xff09; 递归法前序遍历&#xff1a; class Solution:def invertTree(self, root: TreeNode) …

leetcoed123. 买卖股票的最佳时机 III

一&#xff1a;题目 二:上码 class Solution { public:/**思路:1.动态规划五步走1>:确定dp数组以及下标的含义因为题目给出至多完成两笔交易 那么我们一天的状态就有5种0 无操作1 第一次买入2 第一次卖出3 第二次买入4 第二次卖出dp[i][j] 表示的是在第i天 [0,4] 其中某个…

送福利 | 送书3本 ASP.NET Core 真机拆解

小编&#xff1a;最近.NET相关图书在多年沉寂后重新恢复&#xff0c;本书作者提供3本送给公众号粉丝&#xff0c;所以参与方式&#xff1a;文章下方留言&#xff0c;你可以聊聊.NET Core 这几年的发展给你的印象&#xff0c;你的感想&#xff0c;点赞最多的前5位获奖。活动截止…

二叉搜索树基础概念与经典题目(Leetcode题解-Python语言)

二叉搜索树&#xff0c;首先上定义&#xff1a; 节点的左子树只包含小于当前节点的数。节点的右子树只包含大于当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。 而二叉搜索树最有用的性质就是&#xff0c;对其中序遍历可以得到一个递增的有序序列。更多的内容&…

异方差 的 BP检验 方法及原理详解

异方差 的 BP检验详解            文章目录 1. `BP`检验的步骤2. 场景示例步骤 ①步骤 ②BP检验,也称为Breusch-Pagan检验,是一种用于检验线性回归模型中异方差性(即误差项方差不恒定)的统计方法。该方法由Trevor S. Breusch和Adrian R. Pagan在1980年提出。 1.…

leetcode309. 最佳买卖股票时机含冷冻期

一&#xff1a;题目 二:上码 class Solution { public:/**思路:1.分析题意那么我们会有四种状态0 买入股票(或者说是之前就买入了股票但是也一直没有操作)1 卖出股票的状态一 两天前就卖出了股票 但是一直没有操作 2 卖出股票状态二 今天卖出股票3 冷冻期 持续一天2.动态规…

.NET Core 下使用 Exceptionless 记录日志

ExceptionLess是一套免费开源分布式系统日志收集框架&#xff0c;也是我无意中发现的&#xff0c;支持自己部署和平台托管的方式接入使用。ExceptionLess官网&#xff1a;https://exceptionless.comExceptionLess开源地址&#xff1a;https://github.com/exceptionless/Excepti…

高度平衡的二叉搜索树基础概念与经典题目(Leetcode题解-Python语言)

高度平衡的二叉搜索树&#xff08;平衡二叉树&#xff09;&#xff0c;定义见此Leetbook。简单来说&#xff0c;就是基于相同节点值构建出来的二叉搜索树中高度最小的&#xff0c;即为平衡二叉树&#xff08;不唯一&#xff09;。有 N 个节点的平衡二叉搜索树&#xff0c;它的高…