《算法通关之路》学习笔记,记录一下自己的刷题过程,详细的内容请大家购买作者的书籍查阅。
路径总和 II
力扣第113题
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。
from typing import Optional
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
'''
方法一:dfs递归
时间复杂度:O(n)
空间复杂度:最好情况 O(logn)
'''
class Solution:
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> list[list[int]]:
res = []
def dfs(root: TreeNode, targetSum: int, path: list):
if not root:
return
if not root.left and not root. right and targetSum - root.val == 0:
path += [root.val]
res.append(path)
dfs(root.left, targetSum - root.val, path + [root.val])
dfs(root.right, targetSum - root.val, path + [root.val])
dfs(root, targetSum, [])
return res
二叉树中的最大路径和
力扣第124题
二叉树中的 路径 被定义为一条节点序列,序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。
路径和 是路径中各节点值的总和。
给你一个二叉树的根节点 root ,返回其 最大路径和 。
'''
方法一:dfs递归
时间复杂度:O(n)
空间复杂度:最好情况 O(logn)
'''
class Solution:
def maxPathSum(self, root: Optional[TreeNode]) -> int:
max_sum = float('-inf')
def dfs(root: TreeNode):
nonlocal max_sum
if not root:
return 0
max_left = max(dfs(root.left), 0)
max_right = max(dfs(root.right), 0)
max_sum = max(max_sum, max_left + max_right + root.val) # 当前层计算当前层最大路径并保留
return root.val + max(max_left, max_right) # 向上返回根节点+左右子树中路径大的一边
dfs(root)
return max_sum
岛屿数量
力扣第200题
给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
'''
方法一:dfs递归
时间复杂度:O(mn)
空间复杂度:最坏情况 O(mn)
'''
class Solution:
def numIslands(self, grid: list[list[str]]) -> int:
m, n = len(grid), len(grid[0])
cnt = 0
def dfs(r, c):
grid[r][c] = '0'
if c < n - 1 and grid[r][c+1] == '1':
dfs(r, c + 1)
if c > 0 and grid[r][c-1] == '1':
dfs(r, c - 1)
if r > 0 and grid[r-1][c] == '1':
dfs(r-1, c)
if r + 1 < m and grid[r+1][c] == '1':
dfs(r+1, c)
for i in range(m):
for j in range(n):
if grid[i][j] == '1':
dfs(i, j)
cnt += 1
return cnt
# 试运行
grid = [
["1","1","1","1","0"],
["1","1","0","1","0"],
["1","1","0","0","0"],
["0","0","0","0","0"]
]
solu = Solution()
solu.numIslands(grid)
'''
方法二:dfs迭代
时间复杂度:O(mn)
空间复杂度:最坏情况 O(mn)
'''
class Solution:
def numIslands(self, grid: list[list[str]]) -> int:
m, n = len(grid), len(grid[0])
cnt = 0
def dfs(r, c):
grid[r][c] = '0'
stack = [[r, c]]
while stack:
r, c = stack[-1]
if c < n - 1 and grid[r][c+1] == '1':
stack.append([r, c+1])
grid[r][c+1] = '0'
continue
if c > 0 and grid[r][c-1] == '1':
stack.append([r, c-1])
grid[r][c-1] = '0'
continue
if r > 0 and grid[r-1][c] == '1':
stack.append([r-1, c])
grid[r-1][c] = '0'
continue
if r + 1 < m and grid[r+1][c] == '1':
stack.append([r+1, c])
grid[r+1][c] = '0'
continue
stack.pop()
for i in range(m):
for j in range(n):
if grid[i][j] == '1':
dfs(i, j)
cnt += 1
return cnt
# 试运行
grid = [
["1","1","1","1","0"],
["1","1","0","1","0"],
["1","1","0","0","0"],
["0","0","0","0","0"]
]
solu = Solution()
solu.numIslands(grid)
'''
方法三:bfs
时间复杂度:O(mn)
空间复杂度:最坏情况 O(mn)
'''
class Solution:
def numIslands(self, grid: list[list[str]]) -> int:
m, n = len(grid), len(grid[0])
cnt = 0
def bfs(r, c):
grid[r][c] = '0'
queue = [[r, c]]
while queue:
r, c = queue.pop(0)
if c < n - 1 and grid[r][c+1] == '1':
queue.append([r, c+1])
grid[r][c+1] = '0'
if c > 0 and grid[r][c-1] == '1':
queue.append([r, c-1])
grid[r][c-1] = '0'
if r > 0 and grid[r-1][c] == '1':
queue.append([r-1, c])
grid[r-1][c] = '0'
if r + 1 < m and grid[r+1][c] == '1':
queue.append([r+1, c])
grid[r+1][c] = '0'
for i in range(m):
for j in range(n):
if grid[i][j] == '1':
bfs(i, j)
cnt += 1
return cnt
# 试运行
grid = [
["1","1","1","1","0"],
["1","1","0","1","0"],
["1","1","0","0","0"],
["0","0","0","0","0"]
]
solu = Solution()
solu.numIslands(grid)
'''
方法四:并查集
时间复杂度:O(mn×α(mn))
空间复杂度:O(mn)
'''
class UnionFind:
def __init__(self, grid):
m, n = len(grid), len(grid[0])
self.count = 0
self.parent = [-1] * (m * n)
self.rank = [0] * (m * n)
for i in range(m):
for j in range(n):
if grid[i][j] == "1":
self.parent[i * n + j] = i * n + j
self.count += 1
def find(self, i):
if self.parent[i] != i:
self.parent[i] = self.find(self.parent[i])
return self.parent[i]
def union(self, x, y):
rootx = self.find(x)
rooty = self.find(y)
if rootx != rooty:
if self.rank[rootx] < self.rank[rooty]:
rootx, rooty = rooty, rootx
self.parent[rooty] = rootx
if self.rank[rootx] == self.rank[rooty]:
self.rank[rootx] += 1
self.count -= 1
def getCount(self):
return self.count
class Solution:
def numIslands(self, grid: list[list[str]]) -> int:
nr, nc = len(grid), len(grid[0])
uf = UnionFind(grid)
for r in range(nr):
for c in range(nc):
if grid[r][c] == "1":
grid[r][c] = "0"
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":
uf.union(r * nc + c, x * nc + y)
return uf.getCount()
# 试运行
grid = [
["1","1","1","1","0"],
["1","1","0","1","0"],
["1","1","0","0","0"],
["0","0","0","0","0"]
]
solu = Solution()
solu.numIslands(grid)
岛屿数量 II
力扣第305题
给你一个大小为 m x n 的二进制网格 grid 。网格表示一个地图,其中,0 表示水,1 表示陆地。最初,grid 中的所有单元格都是水单元格(即,所有单元格都是 0)。
可以通过执行 addLand 操作,将某个位置的水转换成陆地。给你一个数组 positions ,其中 positions[i] = [ri, ci] 是要执行第 i 次操作的位置 (ri, ci) 。
返回一个整数数组 answer ,其中 answer[i] 是将单元格 (ri, ci) 转换为陆地后,地图中岛屿的数量。
岛屿 的定义是被「水」包围的「陆地」,通过水平方向或者垂直方向上相邻的陆地连接而成。你可以假设地图网格的四边均被无边无际的「水」所包围。
'''
方法一:并查集
时间复杂度:O(klog(mn))
空间复杂度:O(mn)
'''
class UnionFind:
def __init__(self, grid):
m, n = len(grid), len(grid[0])
self.count = 0
self.parent = [0] * (m * n)
self.rank = [0] * (m * n)
def find(self, i):
if self.parent[i] != i:
self.parent[i] = self.find(self.parent[i])
return self.parent[i]
def union(self, x, y):
rootx = self.find(x)
rooty = self.find(y)
if rootx != rooty:
if self.rank[rootx] < self.rank[rooty]:
rootx, rooty = rooty, rootx
self.parent[rooty] = rootx
if self.rank[rootx] == self.rank[rooty]:
self.rank[rootx] += 1
self.count -= 1
def getCount(self):
return self.count
def setCount(self, count):
self.count = count
def setParent(self, i, val):
self.parent[i] = val
class Solution:
def numIslands2(self, m: int, n: int, positions: list[list[int]]) -> list[int]:
answer = []
grid = [[0] * n for _ in range(m)]
uf = UnionFind(grid)
for row, col in positions:
if grid[row][col] == 0:
uf.setCount(uf.getCount() + 1)
uf.setParent(row * n + col, row * n + col)
grid[row][col] = 1
if row > 0 and grid[row-1][col] == 1:
uf.union(row*n+col, (row-1)*n+col)
if row + 1 < m and grid[row+1][col] == 1:
uf.union(row*n+col, (row+1)*n+col)
if col > 0 and grid[row][col-1] == 1:
uf.union(row*n+col, row*n+col-1)
if col + 1 < n and grid[row][col+1] == 1:
uf.union(row*n+col, row*n+col+1)
answer.append(uf.getCount())
return answer
m, n, positions = 3, 3, [[0,0],[0,1],[1,2],[2,1]]
solu = Solution()
solu.numIslands2(m, n, positions)