图论
图论部分推荐 acm 模式,因为图的输入处理不一样
DFS,类似二叉树的递归遍历
BFS,类似二叉树的层次遍历
208. 实现 Trie (前缀树)
数据结构大概如下:
- 可以看成是 二十六叉树 (因为26个小写字母)
py
class Node:
def __init__(self):
self.son = {}
self.end = False # end=True, 表示当前结点已经构成一个单词
class Trie:
def __init__(self):
self.root = Node()
def insert(self, word: str) -> None:
cur = self.root
for c in word:
if c not in cur.son:
cur.son[c] = Node()
cur = cur.son[c]
cur.end = True
def find(self, word: str) -> int:
cur = self.root
for c in word:
if c not in cur.son:
return 0
cur = cur.son[c]
return 2 if cur.end else 1
def search(self, word: str) -> bool:
return self.find(word) == 2
def startsWith(self, prefix: str) -> bool:
return self.find(prefix) != 0
DFS
(1)200. 岛屿数量

方法一:DFS
py
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
dx = [0,-1,0,1]
dy = [-1,0,1,0]
def dfs(i, j):
if (not 0 <= i < m) or (not 0 <= j < n) or grid[i][j] == '0':
return
grid[i][j] = '0'
for idx in range(4):
x = i + dx[idx]
y = j + dy[idx]
dfs(x,y)
m = len(grid)
n = len(grid[0])
ans = 0
for i in range(m):
for j in range(n):
if grid[i][j] == "1":
dfs(i,j) # 把整个岛都标记
ans += 1
return ans
ACM 代码模式: 99. 岛屿数量
读取每一行输入map(int, input().split())
input().split()
,将输入的行,按照空格切分每个元素,返回一个listmap(int, input().split())
,将 list 中每个元素转化为指定的int
类型,返回一个可迭代的对象
例如输入1 2 3 4
input().split()
,得到['1', '2', '3', '4']list(map(int, input().split()))
,[1, 2, 3, 4]
py
dx = [-1,0,1,0]
dy = [0,-1,0,1]
def dfs(i, j):
if not (0<=i<n) or not (0<=j<m) or grid[i][j]==0:
return
grid[i][j] = 0
for idx in range(4):
x = dx[idx] + i
y = dy[idx] + j
dfs(x, y)
if __name__ == '__main__':
n,m = map(int, input().split())
grid = []
for i in range(n):
grid.append(list(map(int, input().split())))
# visited = [ [False] * m for _ in range(n) ]
ans = 0
for i in range(n):
for j in range(m):
if grid[i][j] == 1:
dfs(i, j)
ans += 1
print(ans)
(2)100. 岛屿的最大面积

py
dx = [-1, 0, 1, 0]
dy = [0, -1, 0, 1]
s = 0
def dfs(i, j):
if not (0 <= i < n) or not (0 <= j < m) or grid[i][j] == 0:
return
global s
s += 1
grid[i][j] = 0
for idx in range(4):
x = dx[idx] + i
y = dy[idx] + j
dfs(x, y)
if __name__ == '__main__':
n, m = map(int, input().split())
grid = []
for i in range(n):
grid.append(list(map(int, input().split())))
ans = 0
for i in range(n):
for j in range(m):
if grid[i][j] == 1:
s = 0
dfs(i, j)
ans = max(ans, s)
print(ans)
(3)101. 孤岛的总面积
步骤
- 首先把四周靠边界的岛屿都设为 0
- 然后遍历剩余的孤岛面积
py
dx = [-1,0,1,0]
dy = [0,-1,0,1]
s = 0
def dfs(i,j):
if not (0<=i<n) or not (0<=j<m) or grid[i][j] == 0:
return
global s
s += 1
grid[i][j] = 0
for idx in range(4):
x = dx[idx] + i
y = dy[idx] + j
dfs(x,y)
if __name__ == '__main__':
n, m = map(int, input().split())
grid = []
for i in range(n):
grid.append(list(map(int, input().split())))
# 将四周贴边的非孤岛区域转为水
# 遍历第一列和最后一列
for i in range(n):
if grid[i][0] == 1:
dfs(i,0)
elif grid[i][m-1] == 1:
dfs(i,m-1)
# 遍历第一行和最后一行
for j in range(m):
if grid[0][j] == 1:
dfs(0,j)
elif grid[n-1][j] == 1:
dfs(n-1,j)
# 计算孤岛面积
s = 0
for i in range(n):
for j in range(m):
if grid[i][j] == 1:
dfs(i,j)
print(s)
(4)102. 沉没孤岛

- 把靠四周的非孤岛标记为
2
- 接着把剩余的1(孤岛),标记为
0
- 最后把
2
修改回1
py
dx = [-1,0,1,0]
dy = [0,-1,0,1]
def dfs(i,j):
if not (0 <= i < n) or not(0 <= j < m) or grid[i][j] != 1:
return
grid[i][j] = 2
for k in range(4):
x = dx[k] + i
y = dy[k] + j
dfs(x,y)
if __name__ == '__main__':
n,m = map(int, input().split())
grid = []
for _ in range(n):
grid.append(list(map(int, input().split())))
for i in range(n):
if grid[i][0] == 1:
dfs(i, 0)
if grid[i][m-1] == 1:
dfs(i, m-1)
for j in range(m):
if grid[0][j] == 1:
dfs(0,j)
if grid[n-1][j] == 1:
dfs(n-1, j)
for i in range(n):
for j in range(m):
if grid[i][j] == 1:
grid[i][j] = 0
elif grid[i][j] == 2:
grid[i][j] = 1
print(' '.join(map(str, grid[i])))
BFS
(1)994. 腐烂的橘子
使用 BFS 是为了实现,同一个时间,当前所有腐烂的橘子同时腐烂周围
py
from collections import deque
class Solution:
def orangesRotting(self, grid: List[List[int]]) -> int:
n, m = len(grid), len(grid[0])
q = deque()
count = 0 # 新鲜橘子数
for i in range(n):
for j in range(m):
if grid[i][j] == 1:
count += 1
elif grid[i][j] == 2:
q.append((i,j))
dx = [-1,0,1,0]
dy = [0,-1,0,1]
round = 0 # 分钟数
while count > 0 and len(q) > 0:
round += 1
cur = len(q) # 这一轮有多少个腐烂的橘子一起腐烂周围
for _ in range(cur):
i,j = q.popleft()
for idx in range(4):
x = dx[idx] + i
y = dy[idx] + j
if (0<=x<n) and (0<=y<m) and grid[x][y] == 1:
grid[x][y] = 2
count -= 1
q.append((x,y))
if count > 0:
return -1
else:
return round
(2)207. 课程表

- 每次只能修当前可以修的课程------入度为0的课程
- 修完一轮后,再修可以休的课程------入度变为0的课程
- 所以我们需要记录每个课程的入度,
- 然后需要邻接矩阵来关联课程之间的关系,从而更新入度
py
from collections import deque
class Solution:
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
indegree = [0] * numCourses # 每个课程的入度(即先修课程有几门)
adj = defaultdict(list) # key为当前课,value为它的后续课程,用列表存
# 初始化入度和邻接表
for cur,pre in prerequisites:
indegree[cur] += 1
adj[pre].append(cur)
# 把入度为0的入队列
q = deque()
for i in range(numCourses):
if indegree[i] == 0:
q.append(i)
while q:
n = len(q)
for i in range(n):
pre = q.popleft()
numCourses -= 1
# 遍历课程pre的邻接表:它的后续课程
for cur in adj[pre]:
# 将后续课程的入度 -1
indegree[cur] -= 1
if indegree[cur] == 0:
q.append(cur)
return numCourses == 0