数据规模->时间复杂度
<=10^4 😮(n^2)
<=10^7:o(nlogn)
<=10^8:o(n)
10^8<=:o(logn),o(1)
内容
lc 589 :N 叉树的前序遍历
https://leetcode.cn/problems/n-ary-tree-preorder-traversal/
提示:
节点总数在范围 [0, 104]内
0 <= Node.val <= 104
n 叉树的高度小于或等于 1000
进阶:
递归法很简单,你可以使用迭代法完成此题吗?
#方案一:迭代
"""
# Definition for a Node.
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
class Solution:
def preorder(self, root: 'Node') -> List[int]:
if not root:return []
#
res=[]
stack=list()
stack.append(root)
while stack:
curr=stack.pop()
res.append(curr.val)
#key
for i in range(len(curr.children)-1,-1,-1):
stack.append(curr.children[i])
#
return res
#方案二:递归
"""
# Definition for a Node.
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
class Solution:
def preorder(self, root: 'Node') -> List[int]:
if not root:return []
#
res=[]
self.dfs(root,res)
return res
def dfs(self,node,res):
if not node:return
res.append(node.val)
#key
for children in node.children:
self.dfs(children,res)
# for i in range(len(node.children)):
# self.dfs(node.children[i],res)
lc 590 :N 叉树的后序遍历
https://leetcode.cn/problems/n-ary-tree-postorder-traversal/
提示:
节点总数在范围 [0, 104] 内
0 <= Node.val <= 104
n 叉树的高度小于或等于 1000
进阶:
递归法很简单,你可以使用迭代法完成此题吗?
#方案一:迭代
"""
# Definition for a Node.
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
class Solution:
def postorder(self, root: 'Node') -> List[int]:
if not root:return []
res=list()
stack=[] #list()
stack.append(root)
while stack:
curr=stack.pop()
res.append(curr.val)
#
for childnode in curr.children:
stack.append(childnode) #key
res.reverse()
return res
#方案二:递归
"""
# Definition for a Node.
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
class Solution:
def postorder(self, root: 'Node') -> List[int]:
res=[]
self.dfs(root,res)
return res
def dfs(self,node,res):
if not node:return
#
for child in node.children:
self.dfs(child,res)
res.append(node.val)
lc 429 :N 叉树的层序遍历
https://leetcode.cn/problems/n-ary-tree-level-order-traversal/
提示:
树的高度不会超过 1000
树的节点总数在 [0, 10^4] 之间
#方案一:BFS
"""
# Definition for a Node.
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
class Solution:
def levelOrder(self, root: 'Node') -> List[List[int]]:
if not root:return []
res=[]
queue=deque()
queue.append(root)
while queue:
level_nodes_val=[]
for i in range(len(queue)):
curr=queue.popleft()
level_nodes_val.append(curr.val) #key
for child in curr.children:
queue.append(child)
res.append(level_nodes_val)
return res
#方案二:DFS
"""
# Definition for a Node.
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
class Solution:
def levelOrder(self, root: 'Node') -> List[List[int]]:
res=[]
self.dfs(root,0,res)
return res
def dfs(self,node,currlevel,res):
if not node:return []
#key
if len(res)-1 <currlevel:
res.append([node.val])
else:
res[currlevel].append(node.val)
#
for child in node.children:
self.dfs(child,currlevel+1,res)
lc 690 :员工的重要性
https://leetcode.cn/problems/employee-importance/
提示:
一个员工最多有一个 直系 领导,但是可以有多个 直系 下属
员工数量不超过 2000 。
#方案一:DFS-前序
"""
# Definition for Employee.
class Employee:
def __init__(self, id: int, importance: int, subordinates: List[int]):
self.id = id
self.importance = importance
self.subordinates = subordinates
"""
class Solution:
def getImportance(self, employees: List['Employee'], id: int) -> int:
self.id_map={emp.id:emp for emp in employees} #key:id-emp
self.total=0 #key
self.dfs(id)
return self.total
def dfs(self,id):
emp=self.id_map[id]
if not emp:return
#
self.total+=emp.importance
#
for sub_emp_id in emp.subordinates:
self.dfs(sub_emp_id)
#方案二:DFS-后序
"""
# Definition for Employee.
class Employee:
def __init__(self, id: int, importance: int, subordinates: List[int]):
self.id = id
self.importance = importance
self.subordinates = subordinates
"""
class Solution:
def getImportance(self, employees: List['Employee'], id: int) -> int:
self.id_map={emp.id:emp for emp in employees} #key:id-emp
return self.dfs(id)
def dfs(self,id):
emp=self.id_map[id]
if not emp:return 0
#dfs的时候(self.total=0)先累加子节点值,最后在加根节点(root.importance)
self.total=0 #key:注意位置,
for sub_emp_id in emp.subordinates:
self.total+=self.dfs(sub_emp_id)
return emp.importance+self.total
#方案三:BFS
"""
# Definition for Employee.
class Employee:
def __init__(self, id: int, importance: int, subordinates: List[int]):
self.id = id
self.importance = importance
self.subordinates = subordinates
"""
class Solution:
def getImportance(self, employees: List['Employee'], id: int) -> int:
self.id_map={emp.id:emp for emp in employees} #key:id-emp
return self.bfs(id)
def bfs(self,id):
emp=self.id_map[id]
if not emp:return 0
#
res=0
queue=deque()
queue.append(emp)
while queue:
levelres=0
for i in range(len(queue)):
curr=queue.popleft()
levelres+=curr.importance
for sub_id in curr.subordinates:
queue.append(self.id_map[sub_id]) #key
res+=levelres
return res
图的 DFS 和 BFS:key-遍历过程中,设置节点访问
floodfill 算法基础
#数组二维转一维
#数组一维转二维度
#二维数组的四联通
#二维数组的八联通
#保证索引访问合法
lc 733 :图像渲染
https://leetcode.cn/problems/flood-fill/
提示:
m == image.length
n == image[i].length
1 <= m, n <= 50
0 <= image[i][j], newColor < 216
0 <= sr < m
0 <= sc < n
#方案一:DFS
class Solution:
def floodFill(self, image: List[List[int]], sr: int, sc: int, color: int) -> List[List[int]]:
self.dirs=[[-1,0],[1,0],[0,-1],[0,1]]
self.image=image
self.visited=[[False]*len(self.image[0]) for _ in range(len(self.image))]
self.oldcolor=self.image[sr][sc]
self.dfs(sr,sc,color)
return image
def inarea(self,row,col):
return row>=0 and row<len(self.image) and col>=0 and col<len(self.image[0])
def dfs(self,row,col,newcolor):
#终止条件
if not self.inarea(row,col) or self.image[row][col]!=self.oldcolor:
return
#
self.image[row][col]=newcolor
self.visited[row][col]=True
for dir in self.dirs:
next_row=row+dir[0]
next_col=col+dir[1]
if self.inarea(next_row,next_col):
if not self.visited[next_row][next_col]:
self.dfs(next_row,next_col,newcolor)
#方案二:BFS
class Solution:
def floodFill(self, image: List[List[int]], sr: int, sc: int, color: int) -> List[List[int]]:
self.image=image
self.old_color=image[sr][sc]
if self.old_color == color: #key
return image
self.dirs=[[0,1],[0,-1],[1,0],[-1,0]]
self.bfs(sr,sc,color)
return self.image
def inarea(self,row,col):
return row>=0 and row<len(self.image) and col>=0 and col<len(self.image[0])
def bfs(self,row,col,newcolor):
queue=deque()
queue.append([row,col])
self.image[row][col]=newcolor
while queue:
curr=queue.popleft()
#
for dir in self.dirs: #key1
nextrow=dir[0]+curr[0]
nextcol=dir[1]+curr[1]
if self.inarea(nextrow,nextcol) and self.image[nextrow][nextcol]==self.old_color:
queue.append([nextrow,nextcol]) #key1
self.image[nextrow][nextcol]=newcolor
lc 463 :岛屿的周长
https://leetcode.cn/problems/island-perimeter/
提示:
row == grid.length
col == grid[i].length
1 <= row, col <= 100
grid[i][j] 为 0 或 1
岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连(只有一个岛)
#方案一:DFS-前序
class Solution:
def islandPerimeter(self, grid: List[List[int]]) -> int:
self.grid=grid
self.dirs=[[-1,0],[1,0],[0,-1],[0,1]]
self.visited=[[False]*len(grid[0]) for _ in range(len(grid))]
#
self.ans=0
for i in range(len(self.grid)):
for j in range(len(self.grid[0])):
if self.grid[i][j]==1:
self.dfs(i,j)
return self.ans
def inarea(self,row,col):
return row>=0 and row<len(self.grid) and col>=0 and col<len(self.grid[0])
def dfs(self,row,col):
if not self.inarea(row,col) or self.grid[row][col]==0 or self.visited[row][col]:
return
#
self.visited[row][col]=True
for dir in self.dirs:
nextrow=dir[0]+row
nextcol=dir[1]+col
#key:计边长
if not self.inarea(nextrow,nextcol) or self.grid[nextrow][nextcol]==0:
self.ans+=1
elif not self.visited[nextrow][nextcol]:
self.dfs(nextrow,nextcol)
#方案二:DFS-后序
class Solution:
def islandPerimeter(self, grid: List[List[int]]) -> int:
self.grid=grid
self.dirs=[[-1,0],[1,0],[0,-1],[0,1]]
self.visited=[[False]*len(grid[0]) for _ in range(len(grid))]
#
for i in range(len(self.grid)):
for j in range(len(self.grid[0])):
if self.grid[i][j]==1:
return self.dfs(i,j)
def inarea(self,row,col):
return row>=0 and row<len(self.grid) and col>=0 and col<len(self.grid[0])
def dfs(self,row,col):
if not self.inarea(row,col) or self.grid[row][col]==0:
return 1
if self.visited[row][col]:
return 0 #说明接壤
#
ans=0
self.visited[row][col]=True
for dir in self.dirs:
nextrow=dir[0]+row
nextcol=dir[1]+col
ans+=self.dfs(nextrow,nextcol) #key:基于'四边'情况统计
return ans #对比lc690
#方案三:BFS
class Solution:
def islandPerimeter(self, grid: List[List[int]]) -> int:
self.grid=grid
self.dirs=[[-1,0],[1,0],[0,-1],[0,1]]
self.visited=[[False]*len(grid[0]) for _ in range(len(grid))]
#
for i in range(len(self.grid)):
for j in range(len(self.grid[0])):
if self.grid[i][j]==1:
return self.bfs(i,j)
def inarea(self,row,col):
return row>=0 and row<len(self.grid) and col>=0 and col<len(self.grid[0])
def bfs(self,row,col):
queue=deque()
queue.append([row,col])
self.visited[row][col]=True
#
ans=0
while queue:
curr=queue.popleft()
for dir in self.dirs:
nextrow=curr[0]+dir[0]
nextcol=curr[1]+dir[1]
if not self.inarea(nextrow,nextcol) or self.grid[nextrow][nextcol]==0:
ans+=1
elif not self.visited[nextrow][nextcol]: #key
queue.append([nextrow,nextcol])
self.visited[nextrow][nextcol]=True
return ans
lc 200 :岛屿数量【top100】
https://leetcode.cn/problems/number-of-islands/
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 300
grid[i][j] 的值为 ‘0’ 或 ‘1’
#DFS:
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
self.grid=grid
self.rows=len(grid)
self.cols=len(grid[0])
self.dirs=[[-1,0],[1,0],[0,-1],[0,1]]
self.visited=[[False]*self.cols for _ in range(self.rows)]
#
ans=0
for i in range(self.rows):
for j in range(self.cols):
if self.grid[i][j]=="1" and not self.visited[i][j]:
self.dfs(i,j)
ans+=1
#
return ans
def inarea(self,row,col):
return self.rows>row>=0 and self.cols>col>=0
def dfs(self,row,col):
if not self.inarea(row,col) or self.grid[row][col]=='0' or self.visited[row][col]:
return
self.visited[row][col]=True
for dir in self.dirs:
nextrow=row+dir[0]
nextcol=col+dir[1]
self.dfs(row,col)
lc 695 :岛屿的最大面积
https://leetcode.cn/problems/max-area-of-island/
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 50
grid[i][j] 为 0 或 1
#DFS-后序:
class Solution:
def maxAreaOfIsland(self, grid: List[List[int]]) -> int:
self.grid=grid
self.rows=len(grid)
self.cols=len(grid[0])
self.dirs=[[-1,0],[1,0],[0,-1],[0,1]]
self.visited=[[False]*self.cols for _ in range(self.rows)]
#
maxans=0
for i in range(self.rows):
for j in range(self.cols):
if self.grid[i][j]==1 and not self.visited[i][j]:
maxans=max(self.dfs(i,j),maxans)
#
return maxans
def inarea(self,row,col):
return self.rows>row>=0 and self.cols>col>=0
def dfs(self,row,col):
if not self.inarea(row,col) or self.grid[row][col]==0 or self.visited[row][col]:#key:递归中接壤也是0
return 0
#
self.visited[row][col]=True
ans=0
for dir in self.dirs:
nextrow=row+dir[0]
nextcol=col+dir[1]
ans+=self.dfs(nextrow,nextcol)
return 1+ans
lc 130 :被围绕的区域
https://leetcode.cn/problems/surrounded-regions/
提示:
m == board.length
n == board[i].length
1 <= m, n <= 200
board[i][j] 为 ‘X’ 或 ‘O’
class Solution:
def solve(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
self.rows=len(board)
self.cols=len(board[0])
self.board=board
self.visited=[[False]*self.cols for _ in range(self.rows)]
self.dirs=[[-1,0],[1,0],[0,-1],[0,1]]
#边界
for j in range(self.cols):
if self.board[0][j]=='O' and not self.visited[0][j]:self.dfs(0,j)
if self.board[self.rows-1][j]=='O' and not self.visited[self.rows-1][j]:self.dfs(self.rows-1,j)
for i in range(1,self.rows-1):
if self.board[i][0]=='O' and not self.visited[i][0]:self.dfs(i,0)
if self.board[i][self.cols-1]=='O' and not self.visited[i][self.cols-1]:self.dfs(i,self.cols-1)
#替换
for i in range(self.rows):
for j in range(self.cols):
if self.board[i][j]=='O' and not self.visited[i][j]:
self.board[i][j]='X'
def area(self,row,col):
return 0<=row<self.rows and 0<=col<self.cols
def dfs(self,row,col):
if not self.area(row,col) or self.board[row][col]=='X' or self.visited[row][col]:
return
#
self.visited[row][col]=True
for dir in self.dirs:
nextrow=row+dir[0]
nextcol=col+dir[1]
self.dfs(nextrow,nextcol)
lc 1034 :边框着色
https://leetcode.cn/problems/coloring-a-border/
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 50
1 <= grid[i][j], color <= 1000
0 <= row < m
0 <= col < n
class Solution:
def colorBorder(self, grid: List[List[int]], row: int, col: int, color: int) -> List[List[int]]:
#
self.color=color
self.currcolor=grid[row][col]
if grid[row][col]==color:return grid
#
self.rows=len(grid)
self.cols=len(grid[0])
self.grid=grid
self.visited=[[False]*self.cols for _ in range(self.rows)]
self.dirs=[[-1,0],[1,0],[0,-1],[0,1]]
self.dfs(row,col)
return self.grid
def area(self,row,col):
return 0<=row<self.rows and 0<=col<self.cols
def dfs(self,row,col):
if not self.area(row,col) or self.grid[row][col]!=self.currcolor or self.visited[row][col]:
return
#通过(nextrow,nextcol)对当前顶点判定及递归
self.visited[row][col]=True
for dir in self.dirs:
nextrow=row+dir[0]
nextcol=col+dir[1]
#key条件
if not self.area(nextrow,nextcol) or (self.grid[nextrow][nextcol]!=self.currcolor and not self.visited[nextrow][nextcol]):
self.grid[row][col]=self.color #key-not [nextrow][nextcol]
#
self.dfs(nextrow,nextcol)
lc 529 :扫雷游戏
https://leetcode.cn/problems/minesweeper/
提示:
m == board.length
n == board[i].length
1 <= m, n <= 50
board[i][j] 为 ‘M’、‘E’、‘B’ 或数字 ‘1’ 到 ‘8’ 中的一个
click.length == 2
0 <= clickr < m
0 <= clickc < n
board[clickr][clickc] 为 ‘M’ 或 ‘E’
注:E:未挖空 B:已挖空 M:未挖雷 X:已挖雷
class Solution:
def updateBoard(self, board: List[List[str]], click: List[int]) -> List[List[str]]:
self.rows=len(board)
self.cols=len(board[0])
self.board=board
self.visited=[[False]*self.cols for _ in range(self.rows)]
self.dirs=[[-1,0],[1,0],[0,-1],[0,1],[-1,-1],[-1,1],[1,-1],[1,1]]
#
if board[click[0]][click[1]]=='M':#如果一个地雷('M')被挖出,游戏就结束了- 把它改为 'X'
board[click[0]][click[1]]='X'
else:
self.dfs(click[0],click[1])
return board
def area(self,row,col):
return 0<=row<self.rows and 0<=col<self.cols
def dfs(self,row,col):
if not self.area(row,col) or self.board[row][col]!='E' or self.visited[row][col]:
return
#统计雷数
m_s=0
for dir in self.dirs:
nextrow=row+dir[0]
nextcol=col+dir[1]
if self.area(nextrow,nextcol) and self.board[nextrow][nextcol]=='M':
m_s+=1
#更新board
if m_s>0:
self.board[row][col]=str(m_s)#如果一个 至少与一个地雷相邻 的空方块('E')被挖出,修改它为数字('1' 到 '8' ),表示相邻地雷的数量。
else:
self.board[row][col]='B'
#key位置:如果一个 没有相邻地雷 的空方块('E')被挖出,修改它为('B'),并且所有和其相邻的 未挖出 方块都应该被递归地揭露。
for dir in self.dirs:
nextrow=row+dir[0]
nextcol=col+dir[1]
self.dfs(nextrow,nextcol)
lc 994 :腐烂的橘子
https://leetcode.cn/problems/rotting-oranges/
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 10
grid[i][j] 仅为 0、1 或 2
每分钟,腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。
#多源BFS
class Solution:
def orangesRotting(self, grid: List[List[int]]) -> int:
self.dirs = [[-1, 0], [1, 0], [0, -1], [0, 1]]
self.rows, self.cols = len(grid), len(grid[0])
self.grid=grid
#多源
queue=deque()
for i in range(self.rows):
for j in range(self.cols):
if grid[i][j]==2:
queue.append([i,j])
#
ans=-1
while queue:
for i in range(len(queue)):
curr=queue.popleft()
#
for dir in self.dirs:
nextrow,nextcol=curr[0]+dir[0],curr[1]+dir[1]
#key
if self.area(nextrow,nextcol) and self.grid[nextrow][nextcol]==1:
self.grid[nextrow][nextcol]=2
queue.append([nextrow,nextcol])
ans+=1
#
for i in range(self.rows):
for j in range(self.cols):
if self.grid[i][j]==1:
return -1
return max(ans,0) #[[0]]
def area(self,row,col):
return 0<=row<self.rows and 0<=col<self.cols