【LeetCode算法学习笔记】BFS算法框架

个人学习笔记,记录以便后续复习
个人学习笔记,记录以便后续复习
个人学习笔记,记录以便后续复习

BFS核心思想就是把一些问题抽象成图,从一个点开始,向四周扩散。

算法框架

BFS问题的本质就是在一幅【图】中找到从起点start到终点target的最近距离。
框架如下:

//计算从起点start到终点target的最近距离
int BFS(Node start,Node target){
    Queue<Node> q;//核心数据结构
    Set<Node> visited;//避免回头路
    
    q.offer(start);
    visited.add(start);
    int step=0;
    
    while(q not empty){
        int sz=q.size();
        /*将当前队列中的所有节点向四周扩散*/
        for(int i=0;i<sz;i++){
            Node cur=q.poll();
            /*重点:这里判断是否到达终点*/
            if(cur is target) return step;
            /*将cur的相邻节点加入队列*/
            for(Node x:cur.adj())//cur.adj()泛指cur相邻的节点
                if(x not in visited){
                    q.offer(x);
                    visited.add(x);
                }
        }
        /*重点:在这里更新步数*/
        step++;
    }
}

二叉树的最小高度(111)

*怎么套用到框架里面?*首先,要明确起点start和目标target是什么,怎么判断达到了终点。
(root为start,终点为最靠近根结节点的那个叶节点。)

public class TreeNode{
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x){val=x;}
}
class Solution{
    public int minDepth(TreeNode root){
        Queue<TreeNode> q=new LinkedList<>();
        q.offer(root);
        int depth=1;
        
        if(root==null) return 0;
        
        while(!q.isEmpty()){
            int sz=q.size();
            for(int i=0;i<sz;i++){
            TreeNode cur=q.poll();
            if(cur.left==null && cur.right==null) return depth;
            if(cur.left!=null) minDepth(cur.left);
            if(cur.right!=null) minDepth(cur.right);
            }
            depth++;
        }
        return depth;
    }   
}

BFS的逻辑中,depth每增加一步,队列中所有节点都像前迈一步,齐头并进,可以在不遍历完整课树的条件下找到最短距离的。

解开密码锁密码的最小次数(752)

可以从“0000”开始,转一次,可以穷举出来8个基础密码,然后在这个基础密码上再开始转,直到穷举出所有可能的密码。
可以抽象成为一幅图,一个节点有8个相邻的节点。就是BFS问题。
每一位可以向上波动,也可以向下波动。

class Solution{
    public String plusOne(String s,int j){
        char[] ch=s.toCharArray();
        if(ch[j]=='9') ch[j]='0';
        else ch[j]+=1;
        return new String(ch);
    }
    public String minusOne(Sting s,int j){
        char[] ch=s.toCharArray();
        if(ch[j]=='0') ch[j]='9];
        else ch[j]-=1;
        return new String(ch);
    }
    public int openLock(String[] deadends,String target){
        Set<String> deads=new HashSet<>();
        for(String s:deadends) deads.add(s);
        
        Set<String> visited=new HashSet<>();
        Queue<String> q=new LinkedList<>();
        q.offer("0000");
        visited.add("0000");
        int step=0;
        
        while(!q.isEmpy()){
            String cur=q.poll();
            
            if(deads.contains(cur)) continue;
            if(cur.equals(target)) return step;
            
            for(int j=0;j<4;j++){
                String up=plusOne(cur,j);
                if(!visited.contains(up)){
                    q.offer(up);
                    visited.add(up);
                }
                String down=minusOne(cur,j);
                if(!visitd.contains(down)){
                    q.offer(down);
                    visited.add(down);
                }
            }
        }
        step++;
    }
    return -1;
  }
}

双向BFS优化

传统BFS框架就是从起点开始向四周扩散,遇到终点时停止;而双向BFS则是从起点和终点同时开始扩散,当两边有交集的时候停止。但局限在于你要知道终点在哪里。与BFS框架相比,双向BFS不再使用队列,而是使用HashSet方便快速判断两个集合是否有交集。

public int openLock(String[] deadends,String target){
    Set<String> deads=new HashSet<>();
    for(String s:deadends) deads.add(s);
    //用集合不用队列,可以快速判断元素是否存在
    Set<String> q1=new HashSet<>();
    Set<String> q2=new HashSet<>();
    Set<String> visited=new HashSet<>();
        
    int step=0;
    q1.add("0000");
    q2.add("0000");
    
    //将q1中所有节点向周围扩散  
    while(!q1.isEmpy() && !q2.isEmpty()){
        //哈希集合在遍历的过程中不能修改,用temp存储扩散结果
        Set<String> temp=new HashSet<>();
            
        for(String cur:q1){
            if(deads.contains(cur)) continue;
            if(q2.contains(cur)) return step;
            visited(cur);
                
            for(int j=0;j<4;j++){
                String up=plusOne(cur,j);
                if(!visited.contains(up)) temp.add(up);
                String down=minusOne(cur,j);
                if(!visitd.contains(down)) temp.add(down);
            }
        }
        step++;
        //temp相当于q1
        //这里交换q1,q2,下一轮while就是扩散q2
        q1=q2;
        q2=temp;
 }
 return -1;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值