日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > python >内容正文

python

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

發(fā)布時(shí)間:2023/12/4 python 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 岛屿类问题的广度优先深度优先双解法(Leetcode题解-Python语言) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

695. 島嶼的最大面積

先上最經(jīng)典的題目,詳細(xì)思路看這題的官方題解,簡(jiǎn)單來(lái)說(shuō)的島嶼問(wèn)題就是遍歷二維數(shù)組,一般都是從一塊陸地開(kāi)始,進(jìn)行深度優(yōu)先或者廣度優(yōu)先搜索,每次上下左右四個(gè)方向選其一然后尋找下一塊陸地,最后找到一整個(gè)島嶼(一片陸地)。

廣度優(yōu)先搜索:

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)]) # 隊(duì)列grid[r][c] = 2cur = 1while queue:row, col = queue.popleft() # 先進(jìn)先出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是行的長(zhǎng)度,nc是列的長(zhǎng)度,遍歷整個(gè)二維數(shù)組,如果遇到陸地if grid[r][c] == 1就開(kāi)始找島嶼。廣度優(yōu)先搜索用的是隊(duì)列,記錄的是二維坐標(biāo)。grid[r][c] = 2的目的是防止重復(fù)遍歷。cur是當(dāng)前島嶼的面積。從一塊陸地出發(fā),如果它的四個(gè)方向[(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]的下一個(gè)坐標(biāo)(x, y)在范圍內(nèi)并且為陸地的話(huà),就把它加入隊(duì)列中,同時(shí)標(biāo)記已遍歷,cur也加1。ans記錄最大的島嶼面積。

深度優(yōu)先搜索:

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() # 先進(jìn)后出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

深度優(yōu)先搜索和廣度優(yōu)先搜索基本一樣,只是改用來(lái)實(shí)現(xiàn),每次彈出的位置就是剛剛加入的,即一條路走到底,再往回走(深度);廣度優(yōu)先則按順序彈出,一定把最初的位置遍歷完之后再遍歷新的,如同石頭落入水中產(chǎn)生漣漪(廣度)。

廣度優(yōu)先與深度優(yōu)先切換,只需要改一條初始化語(yǔ)句,一個(gè)pop函數(shù),幾個(gè)變量名就行了。

200. 島嶼數(shù)量

廣度優(yōu)先搜索:

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

深度優(yōu)先搜索:

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

代碼框架基本相同,區(qū)別:這題的數(shù)字用字符來(lái)表示,是“1”而不是1;不需要記錄當(dāng)前島嶼的面積,只需要在進(jìn)入一塊新陸地找島嶼時(shí)ans加1即可,實(shí)際上比上一題簡(jiǎn)單。

694. 不同島嶼的數(shù)量

廣度優(yōu)先搜索:

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)

深度優(yōu)先搜索:

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)

這題找的是不同島嶼的數(shù)量,如何定義島嶼是否相同(模式)呢?題目說(shuō)明:兩個(gè)島嶼被認(rèn)為是相同的,當(dāng)且僅當(dāng)一個(gè)島嶼可以通過(guò)平移變換(不可以旋轉(zhuǎn)、翻轉(zhuǎn))和另一個(gè)島嶼重合。由于我們找陸地時(shí)是從左上向右下找的,所以進(jìn)入某種形狀島嶼的位置是確定的,因此,可以用探索島嶼的路徑(方向組合)來(lái)表示這個(gè)島嶼(類(lèi)似動(dòng)作游戲的上下左右組合技能)。

具體方法就是用字符串記錄這個(gè)方向的組合,同時(shí)要避免不同形狀的島嶼出現(xiàn)相同路徑的情況,在每次遍歷時(shí)加入標(biāo)記path += 'a',保證路徑的唯一性。

463. 島嶼的周長(zhǎng)

廣度優(yōu)先搜索:

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

深度優(yōu)先搜索:

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

本題中只有一個(gè)島嶼,注意周長(zhǎng)即島嶼的邊界,只會(huì)出現(xiàn)在陸地與大邊界或者海洋的交界處,即指向四個(gè)方向的下一個(gè)坐標(biāo)(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. 最大人工島

廣度優(yōu)先搜索:

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)]) # 隊(duì)列grid[r][c] = indexcur = 1while queue:row, col = queue.popleft() # 先進(jìn)先出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

深度優(yōu)先搜索:

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)] # 隊(duì)列grid[r][c] = indexcur = 1while stack:row, col = stack.pop() # 先進(jìn)先出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

一道困難題,基本思路是將現(xiàn)有的島嶼遍歷一次,用字典標(biāo)記不同的島嶼和島嶼面積,然后再遍歷所有的海洋格子,填充該格子后的大島嶼面積就是這個(gè)格子四個(gè)方向的任兩個(gè)島嶼面積之和加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):# 當(dāng)前是遍歷過(guò)的連通分量if (r, c) in explored:return False# 當(dāng)前越界了,說(shuō)明上一次的在網(wǎng)格的邊界上if r < 0 or c < 0 or r == m or c == n:return True# 當(dāng)前不是連通分量,說(shuō)明上一次的與不在分量中的網(wǎng)格相鄰if grid[r][c] != grid[row][col]:return True# 當(dāng)前的是范圍內(nèi)的沒(méi)遍歷過(guò)的連通分量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):# 下一步越界了,說(shuō)明(r,c)在網(wǎng)格的邊界上if r+dx < 0 or c+dy < 0 or r+dx == m or c+dy == n:grid[r][c] = color# 遍歷過(guò)的連通分量跳過(guò)elif (r+dx, c+dy) in explored:continue# 下一步不是連通分量,說(shuō)明(r,c)與不在分量中的網(wǎng)格相鄰elif grid[r+dx][c+dy] != original_color:grid[r][c] = colorelse:stack.append((r+dx, c+dy))return grid

這題指定了遍歷的起點(diǎn) (row, col),所以迭代法實(shí)現(xiàn)中就不能用 for 循環(huán)而要用 while 循環(huán)。從起點(diǎn)出發(fā),記錄下遍歷過(guò)的節(jié)點(diǎn),然后考察其四個(gè)方向的下一個(gè)節(jié)點(diǎn):如果下一個(gè)的節(jié)點(diǎn)越界了,說(shuō)明當(dāng)前節(jié)點(diǎn)在邊界上,則需要著色;如果下一個(gè)節(jié)點(diǎn)是遍歷過(guò)的連通分量,則跳過(guò);如果下一個(gè)節(jié)點(diǎn)不是連通分量,則需要著色;剩下的情況就是下一個(gè)節(jié)點(diǎn)是在邊界內(nèi)的、為遍歷過(guò)的連通分量,則加入棧。

1765. 地圖中的最高點(diǎn)

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

廣度優(yōu)先遍歷,先把所有的 water 方格坐標(biāo)加入隊(duì)列作為起始點(diǎn),然后遍歷它們上下左右的格子,如果是還沒(méi)被遍歷過(guò)的,就在 ans 中高度加 1 并且加入隊(duì)列,直到?jīng)]有格子為止。

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

總結(jié)

以上是生活随笔為你收集整理的岛屿类问题的广度优先深度优先双解法(Leetcode题解-Python语言)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。