lectcode| python的DFS,BFS常用套路模板学习
转载知乎链接:https://zhuanlan.zhihu.com/p/141898546
BFS,DFS的题目思维固定,有一定套路。
BFS模板
构件图的方法有两种
1.用各个节点之间的边表示(邻接矩阵)
如 edges[[0,1],[0,2],[1,4],[2,3],[2,4]]
2. 用节点之间的连接表示(邻接表)
如 [[1,2],
[0,4],
[0,3],
[2],
[1,2]]
第一行代表节点0与1,2相连,以此类推。
以第二种建图
def initial_graph(n, edges): dict_graph = {} # 初始化邻接表 for i in range(n): dict_graph[i] = [] num_e = len(edges) for i in range(num_e): u = edges[i][0] v = edges[i][1] dict_graph[u].append(v) dict_graph[v].append(u) return dict_graph
队列
# 1.使用queue from queue import Queue q = Queue() # 定义,为什么是这样涉及python的设计,不是很懂 q.put(node) # 放入 q.get() # 出队 # 2.使用deque import collections q = collections.deque() # 双向队列 q.append() # 入队 q.popleft() # 出队
节点入队
# 使用Queue()定义 q.put(start_node) # 为防止无向图中回溯,使用set阻断 hash_set = set() hash_set.add(start_node)
BFS背诵部分(注重理解)
step = 0 while not q.empty(): size = len(q) step += 1 for iter_num in range(size): node = q.get() # 节点出队 # get the neighbor for neighbor in dict_graph[node]: if neighbor == end_node: # 找到返回层数 return step if neighbor in hash_set:# 利用set()判断有没有访问过 continue hast_set.add(node) q.put(neighbor) return 0 # 找不到
小结
BFS不难,难在思考用不用它和一些使用时的实现细节:
- BFS的终止条件,一些题目可能不是找到某一终点,而是将图中的某种元素清除。如僵尸吃人的问题,需要将人全部变成僵尸。
- 入队的表示元素可以将(node,step)入队,出队时拆包,从而少些一层循环,进行一定程度上加速。如 wordladder的问题,case给定wordList其实很长。
DFS模板
DFS思路是一条路走到底,撞了墙回头
以找到数组的所有子集为列,对DFS的过程进行描述
数组的子集
已知数组num[1,2,3],要求出它的所有子集
dfs函数定义
因为dfs涉及到程序的递归调用,一般dfs不嵌入到程序内部过程。
在主函数中,dfs作为辅助函数调用
#python中,一般定义如下: def dfsHelper(self, input parameter..., startIndex, tmp, result): """ 其中: input parameter一般指不变的已知量:比如数组num,在矩阵的搜索中指矩阵grid,在图中指图graph和目标节点end_node; startIndex用来标记当前指针在数组(矩阵或者图中的位置),随着递归而改变; tmp:用来暂存递归过程中的结构,随着递归而改变; result:一般为全局变量,用来保存所有的结果。 在程序撰写中,可以定义很多经常使用的量为常量,从而使dfsHelper函数更加短小精悍。 """
DFS递归过程
递归的过程就是先在tmp中加入当前元素,然后调用自身(这中间指针后移),最后在tmp中移除当前元素。
for i in range(startIndex, len(nums)): tmp.append(nums[i]) self.dfsHelper(nums, i + 1, tmp, result) tmp.pop()
DFS的出口
如数组边界,或visited以访问过
完整DFS
DFS求解问题的解法
class Solution: """ @param nums: A set of numbers @return: A list of lists """ def subsets(self, nums): # 从空集开始搜索,每次将nums的节点加入空集中 result = [] tmp = [] if nums is None: return None nums.sort() startIndex = 0 self.dfsHelper(nums, startIndex, tmp, result) return result def dfsHelper(self, nums, startIndex, tmp, result): # dfs出口 tmp_copy = tmp.copy() # 拷贝一份 result.append(tmp_copy) if startIndex == len(nums): return for i in range(startIndex, len(nums)): tmp.append(nums[i]) self.dfsHelper(nums, i + 1, tmp, result) tmp.pop() return