leetcode(14)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]) or grid[i][j] == '0':
return
grid[i][j] = '0'
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
695. 岛屿的最大面积
class Solution:
def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
def dfs(grid, i, j):
# 遇到边界或者遇到0了,就停止
if not 0 <= i < len(grid) or not 0 <= j <len(grid[0]) or grid[i][j] == 0:
return
grid[i][j] = 0
self.res += 1
dfs(grid, i - 1, j)
dfs(grid, i + 1, j)
dfs(grid, i, j - 1)
dfs(grid, i, j + 1)
return self.res
maxS = 0
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == 1:
# 每个岛屿重新计算面积
self.res = 0
dfs(grid, i, j)
maxS = max(maxS, self.res)
return maxS
934. 最短的桥
先通过 DFS 将其中一个岛屿的所有点找出来,放到一个队列 q 中。然后通过 BFS 一层层向外扩展,直至碰到另一个岛屿,此时将当前扩展的层数作为答案返回即可。
在 DFS 和 BFS 搜索的过程中,我们直接将已经访问过的点标记为 2,这样就不会重复访问。
class Solution:
def shortestBridge(self, grid: List[List[int]]) -> int:
def dfs(i, j):
q.append((i, j))
grid[i][j] = 2
for a, b in pairwise(dirs):
x = i + a
y = j + b
if 0 <= x < n and 0 <= y < n and grid[x][y] == 1:
dfs(x, y)
n = len(grid)
dirs = (-1, 0, 1, 0, -1)
q = deque()
i, j = next((i, j) for i in range(n) for j in range(n) if grid[i][j])
dfs(i, j)
res = 0
while 1:
for _ in range(len(q)): # 注意是q的层数
i, j = q.popleft() # 注意是弹出左边的
for a, b in pairwise(dirs):
x = i + a
y = j + b
if 0 <= x < n and 0 <= y < n:
if grid[x][y] == 1:
return res
elif grid[x][y] == 0:
grid[x][y] = 2
q.append((x, y))
res += 1
79. 单词搜索
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
dire = [(0,-1),(0,1),(1,0),(-1,0)]
def dfs(i, j, k):
if board[i][j] != word[k]:
return False
if k == len(word) - 1:
return True
visited.add((i, j))
for x, y in dire:
newi, newj = i + x, j + y
if 0 <= newi < col and 0 <= newj < row:
if (newi, newj) not in visited:
if dfs(newi, newj, k + 1):
return True
visited.remove((i, j))
return False
visited = set()
col, row = len(board), len(board[0])
for i in range(col):
for j in range(row):
if dfs(i, j, 0):
return True
return False
808. 分汤
记忆化搜索
由于每次操作都是 25 的倍数,因此,我们可以将每 25ml 的汤视为一份。这样就能将数据规模缩小到$ \left \lceil \frac{n}{25} \right \rceil$
class Solution:
def soupServings(self, n: int) -> float:
n = (n + 24) // 25
if n >= 179:
return 1.0
@cache
def dfs(i, j):
if i <= 0 and j <= 0:
return 0.5
if i <= 0:
return 1
if j <= 0:
return 0
return 0.25 * (dfs(i - 4, j) + dfs(i - 3, j - 1) +
dfs(i - 2, j - 2) + dfs(i - 1, j - 3))
return dfs(n, n)
6255. 两个城市间路径的最小分数
反正跟节点1连接的所有节点都能到达n,就直接遍历从节点1发散下去的所有路径,并记录在res里
class Solution:
def minScore(self, n: int, roads: List[List[int]]) -> int:
g = [[] for _ in range(n + 1)]
for a, b, d in roads:
g[a].append((b, d))
g[b].append((a, d))
# print(g)
q = g[1]
vis = set()
vis.add(1)
res = []
for x, v in g[1]:
res.append(v)
while q:
x, v = q.pop()
for y, d in g[x]:
if y not in vis:
q.append((y, d))
vis.add(x)
res.append(d)
return min(res)