• BFS模板


    模板,记住这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(大部分提供解答)
    

      

  • 相关阅读:
    急招.NET系列职位
    程序员成长的三个方法
    xwebkitspeech
    张小龙的产品
    浅析商业银行“业务连续性管理体系”的构建
    Sonar for dotNet
    Moles测试Contrustor时候遇到的一个问题
    EntityFramework 用Moles的mock
    Accessor中Generic的元素是internal/private的会导致转换失败的异常
    Android自用Intent 介绍
  • 原文地址:https://www.cnblogs.com/bonelee/p/12588965.html
Copyright © 2020-2023  润新知