模板,记住这5个: (1)针对树的BFS 1.1 无需分层遍历 from collections import deque def levelOrderTree(root): if not root: return q = deque([root]) while q: head = q.popleft() do something with this head node... if head.left: q.append(head.left) if head.right: q.append(head.right) return xxx 1.2 需要分层遍历 def levelOrderTree(root): if not root: return q = [root] while q: new_q = [] for node in q: # 和上面代码相比 差异就在这里 和 deque do something with this layer nodes... if node.left: new_q.append(node.left) if node.right: new_q.append(node.right) q = new_q return xxx (2)针对图的BFS 2.1 无需分层遍历 from collections import deque def bfs_graph(root): if not root: return queue = deque([root]) seen = set([root]) while queue: head = queue.popleft() do something with this head... for neighbor in head.neighbors: if neighbor not in seen: # 和tree的区别无非就是多了一个是否访问过的判断 seen.add(neighbor) queue.append(neighbor) return xxx 上述代码中: neighbor 表示从某个点 head 出发,可以走到的下一层的节点。 set/seen 存储已经访问过的节点(已经丢到 queue 里去过的节点) queue 存储等待被拓展到下一层的节点 set/seen 与 queue 是一对好基友,无时无刻都一起出现,往 queue 里新增一个节点,就要同时丢到 set 里。 需要分层遍历的宽度搜先搜索 2.2 需分层遍历 def bfs_graph(root): if not root: return [] q = [root] seen = set([root]) while q: new_q = [] for node in q: do something with this layer nodes... for neighbor in node.neighbors: if neighbor not in seen: # 和tree的区别无非就是多了一个是否访问过的判断 seen.add(neighbor) new_q.append(neighbor) q = new_q return xxx (3)拓扑排序 记住下面的代码 class Solution: """ @param graph: A list of Directed graph node @return: Any topological order for the given graph. """ def topSort(self, graph): node_to_indegree = self.get_indegree(graph) # bfs order = [] start_nodes = [n for n in graph if node_to_indegree[n] == 0] queue = collections.deque(start_nodes) while queue: node = queue.popleft() order.append(node) for neighbor in node.neighbors: node_to_indegree[neighbor] -= 1 if node_to_indegree[neighbor] == 0: queue.append(neighbor) return order def get_indegree(self, graph): node_to_indegree = {x: 0 for x in graph} for node in graph: for neighbor in node.neighbors: node_to_indegree[neighbor] += 1 return node_to_indegree 算法流程 拓扑排序的算法是典型的宽度优先搜索算法,其大致流程如下: 统计所有点的入度,并初始化拓扑序列为空。 将所有入度为 0 的点,也就是那些没有任何依赖的点,放到宽度优先搜索的队列中 将队列中的点一个一个的释放出来,放到拓扑序列中,每次释放出某个点 A 的时候,就访问 A 的相邻点(所有A指向的点),并把这些点的入度减去 1。 如果发现某个点的入度被减去 1 之后变成了 0,则放入队列中。 直到队列为空时,算法结束 一些实际案例: https://www.cnblogs.com/bonelee/p/11724346.html
BFS宽度优先搜索 模板: https://www.cnblogs.com/bonelee/p/11724346.html BFS模板: def levelOrder(self, root): # write your code here if not root: return [] q = [root] result = [] while q: children = [] q2 = [] for node in q: children.append(node.val) if node.left: q2.append(node.left) if node.right: q2.append(node.right) result.append(children) q = q2 return result BFS 递归实现 q= [root] result = [] def levelOrder(q): if not q: return q2 = [] for node in q: xxxx if node.left: q2.append(node.left) if node.right: q2.append(node.right) levelOrder(q2) 1. BFS VS DFS https://www.geeksforgeeks.org/difference-between-bfs-and-dfs/ 2. 什么时候使用BFS 图的遍历 Traversal in Graph • 层级遍历 Level Order Traversal • 由点及面 Connected Component • 拓扑排序 Topological Sorting 最短路径 Shortest Path in Simple Graph • 仅限简单图求最短路径 • 即,图中每条边长度都是1,或者边长都相等 非递归的方式找所有方案 Iteration solution for all possible results • 这一点我们将在后面 DFS 的课上提到 3. 题型与算法的对应关系 最短路径 简单图 → BFS 复杂图 → Dijkstra, SPFA, Floyd(一般面试不考这个) 最长路径 图可以分层 → Dynamic Programming 分层:比如走到第i一定会经过第 i-1 层(棋盘格子图是典型的例子) 不可以分层 → DFS 4.主要内容 • 二叉树上的 BFS • 图上的 BFS • 矩阵上的 BFS • 拓扑排序 Topological Sorting 5. 二叉树上的 BFS 5.1 二叉树层级遍历 5.1.1 非递归实现方法讲解 https://blog.csdn.net/sinat_20177327/article/details/78285495 5.1.2 题目和非递归python实现 https://blog.csdn.net/yurenguowang/article/details/76906620 5.1.3 DFS递归方法和java实现 https://blog.csdn.net/crazy1235/article/details/51507485 5.2 二叉树的序列化 5.2.1 什么是序列化(P11) 将“内存”中结构化的数据变成“字符串”的过程 序列化:object to string 反序列化:string to object 5.2.2 什么时候需要序列化(P12) 1. 将内存中的数据持久化存储时 内存中重要的数据不能只是呆在内存里,这样断电就没有了,所需需要用一种方式写入硬盘,在需要的 时候,能否再从硬盘中读出来在内存中重新创建 2. 网络传输时 机器与机器之间交换数据的时候,不可能互相去读对方的内存。只能讲数据变成字符流数据(字符串)后 通过网络传输过去。接受的一方再将字符串解析后到内存中。 5.2.3 序列化算法(P13) 一些序列化的例子: • 比如一个数组,里面都是整数,我们可以简单的序列化为”[1,2,3]” • 一个整数链表,我们可以序列化为,”1->2->3” • 一个哈希表(HashMap),我们可以序列化为,”{\”key\”: \”value\”}” 序列化算法设计时需要考虑的因素: • 压缩率。对于网络传输和磁盘存储而言,当然希望更节省。 • 如 Thrift, ProtoBuf 都是为了更快的传输数据和节省存储空间而设计的。 • 可读性。我们希望开发人员,能够通过序列化后的数据直接看懂原始数据是什么。 • 如 Json,LintCode 的输入数据 5.2.4 使用BFS序列化 题目 https://www.lintcode.com/problem/serialize-and-deserialize-binary-tree/description python BFS解答 https://www.jiuzhang.com/solutions/binary-tree-serialization/#tag-highlight-lang-python 5.3 二叉树上的BFS相关题目 5.3.1 Binary Tree Level Order Traversal II 题目: http://www.lintcode.com/en/problem/binary-tree-level-order-traversal-ii/ 解答: https://blog.csdn.net/coder_orz/article/details/51583729 http://www.jiuzhang.com/solutions/binary-tree-level-order-traversal-ii/ 5.3.2 Binary Tree Zigzag Order Traversal http://www.lintcode.com/en/problem/binary-tree-zigzag-level-order-traversal/ http://www.jiuzhang.com/solutions/binary-tree-zigzag-level-order-traversal/ 5.3.3 Convert Binary Tree to Linked Lists by Depth http://www.lintcode.com/en/problem/convert-binary-tree-to-linked-lists-by-depth/ http://www.jiuzhang.com/solutions/convert-binary-tree-to-linked-lists-by-depth/ leetcode lintcode(大部分提供解答)