算法总结五:BFS你也能出错?不该!

本文详细介绍了BFS(宽度优先搜索)算法,包括在二叉树的层次遍历、拓扑排序、连通分量等问题中的应用。强调了BFS通常使用队列实现,并指出BFS适用于解决最短路径问题。同时,提供了多个算法题目的解析,涉及矩阵、图、二叉树等,如最短路径、岛屿数量等。
摘要由CSDN通过智能技术生成

一。Breadth-First Search宽度优先:
从根节点开始,沿着树(图)的宽度遍历树(图)的节点。 如果所有节点均被访问,则算法中止。

在这里插入图片描述

宽度优先算法的遍历顺序为:1->2->3->4->5->6->7->8 from jianshu.com
什么时候用BFS?
level order traversal in binary tree
topological sorting
connected component(islands)

二。BFS的套路:
无特殊情况,BFS就用queue(队列)实现!!!
由于需要横向一层一层遍历,有时还要利用层数。
算法中引入一个FIFO的queue
第一次q.size()拿到第一层,然后用for循环吐完,expand完,generate完子节点;
第二次进入for循环就是第二层的数量了。依次执行知道q为空。
通常题目中提及“最短路径”用BFS,可以得到满足条件且路径最短(层数最少)的解。

	void bfs(){
   
       q.offerFirst(Arrays.asList(0,0);     //将首节点加入队列            
       visited[0][0]=true;                  //标记首节点已经被访问
       while(!q.empty()){
   
       		int size=q.size();
       		for(int i=0;i<size;i++){
   
	            List<Integer> cur=q.pollLast();
	            Integer nextX=cur.get(0)+dir[0];
	            Integer nextY=cur.get(0)+dir[0];
	            if(next is legal){
   
	            	q.offerFirst(next);  //入队,同时计数或维护等; 
	            }
           } 
        }  
	}

引用其它博客总结,能用DFS做的算法题,用BFS也能做。而且有限用BFS做,不容易出错。

3.算法题:

算法分类
3.1.binary tree中的BFS
(129,101,662,863,987)
129. Sum Root to Leaf Numbers
BFS

class Solution {
   
    public int sumNumbers(TreeNode root) {
   
        Queue<TreeNode>q = new LinkedList<>();
        int sum = 0;
        if(root == null)
            return sum;
        q.add(root);
        while(!q.isEmpty()) {
   
            TreeNode temp = q.remove();
            if(temp.left == null && temp.right == null){
   
                sum += temp.val;
            }else {
   
                if(temp.left!= null) {
   
                    int cur = temp.val * 10 + temp.left.val;
                    temp.left.val = cur;
                    q.add(temp.left);
                } 
                if(temp.right!= null) {
   
                    int cur = temp.val * 10 + temp.right.val;
                    temp.right.val = cur;
                    q.add(temp.right);
                }
            }
        }
        return sum;
    }
}

DFS

class Solution {
   
    int sum;
    public int sumNumbers(TreeNode root) {
   
        sum=0;
        dfs(root,0);
        return sum;
    }
    public void dfs(TreeNode node,int num){
   
        //base case//reach the bottom, return
        if(node==null){
    
            return;
        } 
        //else: cur level : do sth
        num=num*10+node.val;
        if(node.left==null && node.right==null){
   //BUG: if reach leaf, then accumulate total sum
            sum+=num;
        }
        //recursion rule: 小一号问题shi什么?
        dfs(node.left,num);//往下走,
        dfs(node.right,num);
         
    }
}

101. Symmetric Tree
BFS
//每次两个两个poll出来处理


public boolean isSymmetric(TreeNode root) {
   
    Queue<TreeNode> q = new LinkedList<>();
    q.add(root);
    q.add(root);
    while (!q.isEmpty()) {
   
        TreeNode t1 = q.poll();
        TreeNode t2 = q.poll();
        if (t1 == null && t2 == null) continue;
        if (t1 == null || t2 == null) return false;
        if (t1.val != t2.val) return false;
        q.add(t1.left);
        q.add(t2.right);
        q.add(t1.right);
        q.add(t2.left);
    }
    return true;
}

recursion

class Solution {
   
    public boolean isSymmetric(TreeNode root) {
   
        if(root==null) return true; //null
        return recurseSymm(root,root);
    }
    public boolean recurseSymm(TreeNode a,TreeNode b){
   
    //base case
        if(a==null && b==null) return true; 
        if(a==null || b==null){
   
            return false;
        }
        //recursion rule ---->bug 没有写 a.val==b.val 
        //cur level: the value should be the same
        return a.val==b.val && recurseSymm(a.left,b.right) && recurseSymm(a.right,b.left); 
    }
}

662. Maximum Width of Binary Tree

class Solution {
   
    public int widthOfBinaryTree(TreeNode root) {
   
        if(root==null) return 0;
        
        //bfs
        //interface
        Pair<TreeNode, Integer> start=new Pair<>(root,0);
      LinkedList<Pair<TreeNode, Integer>> q = new LinkedList<>();
        q.offerLast(start);
        int maxWidth = 0;
        
        while(!q.isEmpty()){
   
             Pair<TreeNode,Integer> head = q.getFirst(); //每次取一下第一个
            
            int size=q.size();
            int index=0;//放在外头声明
            Pair<TreeNode,Integer> curPair=null;
            
            for(int i=0;i<size;i++){
   
                curPair=q.pollFirst();
                TreeNode cur=curPair.getKey();
                index=curPair.getValue();

                if(cur.left != null){
   
                    q.offerLast(new Pair(cur.left,2*index));//问题:每一层index怎么加?如果遇到 2 3 null 9?
                }
                if(cur.right != null){
   
                    q.offerLast(new Pair(cur.right,2*index+1));  //不用+1的方式,是固定的2*idx+1
                }
            }
            
               // calculate the length of the current level,
            //   by comparing the first and last col_index.
            maxWidth = Math.max(maxWidth, index - head.getValue() + 1);
        }
        return maxWidth;
            
        }
    }

987. Vertical Order Traversal of a Binary Tree

    /*
            1(0,0)
          /   \
 (1,-1) 2       3 (1,1)
      / \       / \
     4   5     6    7
(2,-2)    (2,0)      (2,2)
    */

这里不光用了new的class,还应用了自定义泛型。学起来!
//root.first:val
//root.second:row 0
//root.third:col 0
难点:
假如当前我不知道col的号码都是多少,
如何将每一个node的值加入到res中?
排序之后:<4(2,-2) >,<2 (1,-1) >,< 1(0,0)>,<5(2,0)>,<6(2,0)>,< 3 (1,1)>,<7(2,2)>;
先拿第一个作为curColumnIndex作为参照系。

 List<Integer> curColumn=new ArrayList<Integer>();
 Integer curColumnIndex=list.get(0).third;
 for( Coord<Integer,Integer,Integer> c:list){
   
                Integer column=c.third,value=c.first;
                if(column==curColumnIndex){
   
                    curColumn.add(value);//column同样都是0时,加1,加5,加6
                }else{
   
                    res.add(curColumn);
                    curColumnIndex=column;//column从-2转到-1,转到0
                    curColumn=new ArrayList();//都需要新的ArrayList
                    curColumn.add(value);
                }
            }

完整解法:

class Solution {
   
    public List<List<Integer>> verticalTraversal(TreeNode root) {
   
        List<List<Integer>> res=new ArrayList<>();
        if(root==null) return res;
        
        bfs(root);
        //bfs遍历 +pack <TreeNode,row,col> in Queue+add to list layer by layer
        //才能按照val,row,col排序
        Collections.sort(list,(c1,c2)->{
   
            if(c1.third.equals(c2.third)){
   
                 if(c1.second.equals(c2.second)){
   
                      return c1.first-c2.first;
                 }else{
   
                      return c1.second-c2.second;
                 }
            }else{
   
                  return c1.third-c2.third;
            }
        });
        
        List<Integer> curColumn=new ArrayList<Integer>();
            Integer curColumnIndex=list.get(0).third;

            for( Coord<Integer,Integer,Integer> c:list){
   
                Integer column=c.third,value=c.first;
                if(column==curColumnIndex){
   //0
                    curColumn.add(value);
                }else{
   
                    res.add(curColumn);//?????????????
                    curColumnIndex=column;
                    curColumn=new ArrayList();
                    curColumn.add(value);
                }
            }
            res.add(curColumn);
            return res; 
    }
    
    //bfs +pack <TreeNode,row,col> in Queue+add to list layer by layer 
    List<Coord<Integer,Integer,Integer>> list=new ArrayList<>();
    private void bfs(TreeNode root){
   
        Queue<Coord<TreeNode, Integer, Integer>> q=new ArrayDeque<>();
        int row=0;
        int col=0;
        
        q.offer(new Coord(root,row,col));
        while(!q.isEmpty()){
   
            Coord<TreeNode, Integer, Integer> cur=q.poll();
            root=cur.first;
            row=cur.second;
            col=cur.third;
            if(root!=null){
    
                list.add(new Coord(root.val,row,col));
                q.offer(new Coord(root.left,row+1,col-1));
                q.offer(new Coord(root.right,row+1,col+1));
            }
        }
    }
    
    class Coord<F,S,T>{
     //bug
        public final F first;
        public final S second;
        public final T third;
        public Coord(F first,S second,T third){
   
            this.first=first; //r
            this.second=second; //c
            this.third=third; //val
        }
    }
}

3.2.graph中的BFS(topological sorting)
(127,133,210,310,743,1129,1311,847,1345)
Topological Sorting

Topological sorting for Directed Acyclic Graph (DAG) is a linear ordering of vertices such that for every directed edge u v, vertex u comes before v in the ordering. Topological Sorting for a graph is not possible if the graph is not a DAG.

It does not allows cycle in the graph. Like prerequisite class, if the graph has a cycle, which means one class would be its own prerequisite. That would be illogical.
Topological Sorting helps to check whether there is a cycle in the graph.
if all vertex will be add to topo-ordered-list, then it’s acyclic. Otherwise, there are some vertex left and cannot be add to the list, it’s cyclic.


AOV:Activity On Vertex
AOE: Activity On Edge

133. Clone Graph
BFS

class Solution {
   
    Map<Node,Node> copied;
    public Node cloneGraph(Node node) {
   
        if (node == null) {
   
            return node;
        }
        copied=new HashMap<>();
        Node copyNode=new Node(node.val );//bug: new Node 的时候,new ArrayList<>()
        copied.put(node,copyNode);
        //BFS
        Queue<Node> q=new LinkedList<>();
        q.offer(node);
        while(!q.isEmpty()){
   
            Node cur=q.poll(); //1
            if(cur.neighbors!=null){
   
                for(Node n:cur.neighbors){
   //2,4
                    if(!copied.containsKey(n)){
   
                        Node newNode=new Node(n.val);//2'
                        copied.put(n,newNode);
                        q.offer(n);//bug2  forget to offer n
                    } 
                    copied.get(cur).neighbors.add(copied.get(n));
                }
            }
        }
        return copied.get(node);// return from the copied map
    }
}

DFS

class Solution {
   
    private HashMap <Node, Node> visited = new HashMap <> ();
    public Node cloneGraph(Node node) {
   
        //1.base case
        if (node == null) {
   
            return node;
        }
        // If the node was already visited before.
        // Return the clone from the visited dictionary.
        if (visited.containsKey(node)) {
   
            return visited.get(node);
        }
        //2.recursion rule: else : node != null && !visited.containsKey(node)
        // Create a clone for the given node.
        // Note that we don't have cloned neighbors as of now, hence [].
        Node cloneNode = new Node(node.val, new ArrayList());
        // The key is original node and value being the clone node.
        visited.put(node, cloneNode);
        // Iterate through the neighbors to generate their clones
        // and prepare a list of cloned neighbors to be added to the cloned node.
        for (Node neighbor: node.neighbors) {
   
            cloneNode.neighbors.add(cloneGraph(neighbor));
            //key point: cloneGraph(neighbor) return the copied node...
        }
        return cloneNode;
    }
}

(Topological Sorting)
207. Course Schedule
难点: return removedEdges==totalEdges;
如果移除的边和总的边数一样多,那么说明没有环,topological sorting正常进行。课程设置没有问题。

class Solution {
   
    public boolean canFinish(int numCourses, int[][] prerequisites) {
   
        int totalEdges=prerequisites.length;
         
        int[] indeg=new int[numCourses];
        //build the graph
        for(int[] edge: prerequisites){
    
            indeg[edge[0]]++;
        }
        
        Queue<Integer> q=new LinkedList<>();
        
        for (int i = 0; i < numCourses; i++) {
   
            if (indeg[i] == 0) q.offer(i);//特别  :+0
        }  //[[1,0],[2,1],[3,1]]
        int removedEdges = 0;
        while(!q.isEmpty()){
    //
            int cur=q.poll();//0
            for(int[] edge: prerequisites){
   
                if(cur==edge[1]){
   //0
                    indeg[edge[0]]--;  //indeg[1] --
                    removedEdges++;
                    if(indeg[edge[0]] == 0){
     //indeg[1]==0
                        q.offer(edge[0]);
                    }//我的bug出在,这个if的判断写在了上一个if的外头,与之并列了。
                    //logic here: when the cur==0; indeg[1]--, 
                    //1 becomes the one with indegree==0,offer 1 into the q.
                } 
            }      
        }
        return removedEdges==totalEdges;//check if remove n edges in the topo sorting, all has been offer and poll.//which means, prereq and later courses are all satisfied.there is no cycle inside.
    }
}

(Topological Sorting)
210. Course Schedule II
难点:嵌套的int[]中

        for (int[] edge : prerequisites) {
   
            inDeg[edge[0]]++;
        }

什么时候用edge[0],什么时候用edge[1]。
什么时候inDeg[edge[0]]++;什么时候inDeg[edge[0]]–;

class Solution {
   
    public int[] findOrder(int numCourses, int[][] prerequisites) {
   
        List<Integer> res = new ArrayList<>();
        int[] inDeg = new int[numCourses];
        for (int[] edge : prerequisites) {
   
            inDeg[edge[0]]++;
        }
        Queue<Integer> queue = new ArrayDeque<>();
        for (int i = 0; i < numCourses; i++) {
   
            if (inDeg[i] == 0) queue.offer(i);
        }
        while (!queue.isEmpty()) {
   
            Integer cur = queue.poll();
            res.add(cur);
            for (int[] edge : prerequisites) {
   
                if (cur == edge[1]) {
   
                    inDeg[edge[0]]--;
                    if (inDeg[edge[0]] == 0) {
   
                        queue.offer(edge[0]);
                    }
                }
            }
        }
        int[] resArray = new int[numCourses];
        if (res.size() == numCourses) {
   
            for (int i = 0; i < numCourses; i++) {
   
                resArray[i] = res.get(i);
            }
        }
        return res.size() == numCourses ? resArray : new int[0];
    }
}

(topological sorting)
310. Minimum Height Trees
youtube中文solution
21天高频复习计划
想象把一个点拿出来当根,然后从叶子结点(indegree==1)这层开始offer,
每次删除叶子结点,最后剩下的一层,就是根。
如果剩下两个,就有两个都可以作为根的节点

class Solution {
   
    public List<Integer> findMinHeightTrees(int n, int[][] edges) {
   
        List<Integer> res=new ArrayList<>();
        if(n==1) {
   
            res.add(0);
            return res;
        }
        
        int[] indeg=new int[n]; //[3,0]
        Map<Integer,List<Integer>> map=new HashMap<>();
        for(int i=0;i<n;i++) map.put(i,new ArrayList<>());
        
        for(int[] edge:edges){
   
            map.get(edge[0]).add(edge[1]);
            map.get(edge[1]).add(edge[0]);
            indeg[edge[0]]++; //indeg[3]
            indeg[edge[1]]++;//indeg[0]
        }
        
        Queue
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值