BFS练手题目

广度优先搜索(BFS)算法,概念就不说啥了,常用来求最短路径,最少步数等,比如求二叉树最小高度。

BFS与DFS:简单理解就是DFS找会先沿着一条路径一直往深处走走到头在往回退重重这个过程。BFS则是沿着多个可选路径齐头并进,每次只向前走一小步,最终哪条路径先走到终点则走的步数就是最短路径。BFS先空间复杂度相比于DFS较高,时间复杂度最坏为O(N).

总体解体框架参考labuladong的算法小抄中的结构,如下图所示:

在这里插入图片描述

核心数据结构为一个queue,需要用这个queue记录每一层次的数据节点,还有一个visited记录已经访问过的数据(使用set或者其他结构来),还有一个step来控制扩散的层数(步数)。具体做题感受吧。

这里记录了几个经典例题:

1.员工的重要性

https://leetcode.cn/problems/employee-importance/

在这里插入图片描述

这个题可以用bfs来做,员工信息用map关联起来方便查询。

class Solution {
public:
    int getImportance(vector<Employee*> employees, int id) {
        if(employees.empty()) return 0;
        for(auto e:employees)
            mp1[e->id]=e;

BFS
        queue<int>  q1;
        q1.push(id);
        while(!q1.empty()){
            sum += mp1[q1.front()]->importance;
            for(auto e: mp1[q1.front()]->subordinates)
            {
                q1.push(e);
            }
            q1.pop();
        }
        return sum;        
    }
private:
    int sum=0;
    unordered_map<int,Employee*> mp1;
};

2.腐烂的橘子

https://leetcode.cn/problems/rotting-oranges/

在这里插入图片描述
类似于图像渲染,一层一层向外扩散,很明显要BFS来求最短步数。

这里我用了Node结构体来封装x,y坐标,方便访问,也可以使用pair<int,int>结构。
这个题刚开始练手做的,感觉代码写的不是很好。

class Solution {
public:
    struct Node{
        Node(int _x,int _y):x(_x),y(_y)
        {}
        int x;
        int y;
    };

    int orangesRotting(vector<vector<int>>& grid) {
        int  row=grid.size();
        int col=grid[0].size();
        if(grid.empty()) return -1;
        
        vector<vector<bool>>  visited(row,vector<bool>(col,false));
        queue<Node> q1;  
        
        int suma=0,sumb=0;//suma 为橘子数,sumb为入队的橘子数
        
        for(int i=0;i<row;++i){    //初始节点入队
            for(int j=0;j<col;++j){
                if(grid[i][j]!=0) suma++;
                if(grid[i][j]==2){  //可能有多个腐烂的橘子
                    q1.push(Node(i,j));
                    visited[i][j]=true;
                }
            }
        }

        int deep=0; 
        while(!q1.empty()){
            deep++;
            int size=q1.size();
            while(size--){
                Node node1=q1.front();
                q1.pop();
                sumb++;   
                for(int i=0;i<4;++i){   //坐标扩散
                    int x =node1.x + nextposition[i][0];
                    int y =node1.y + nextposition[i][1];
                    if(x>=0 && x<row && y>=0 && y<col
                        &&grid[x][y]==1   
                        && visited[x][y]==false){
                        q1.push(Node(x,y));
                        visited[x][y]=true;
                        //grid[x][y]=2;
                    }
                }  
    
            }
        }
        if(suma==0) return 0;
        return suma==sumb? deep-1:-1;
    }
private:
    int nextposition[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
};

3.N 叉树的层序遍历

https://leetcode.cn/problems/n-ary-tree-level-order-traversal/

在这里插入图片描述

/*
// Definition for a Node.
class Node {
public:
    int val;
    vector<Node*> children;

    Node() {}

    Node(int _val) {
        val = _val;
    }

    Node(int _val, vector<Node*> _children) {
        val = _val;
        children = _children;
    }
};
*/

class Solution {
public:
    vector<vector<int>> levelOrder(Node* root) {
        vector<vector<int>> retv;
        if(!root) return retv;
        queue<Node*> q1;
        q1.push(root);

        while(!q1.empty()){
            vector<int> v1;
            int size=q1.size();
            
            while(size--){
                Node* n1=q1.front();
                q1.pop();   
                for(auto e : n1->children){
                    q1.push(e);
                }
                v1.push_back(n1->val);
            }
            retv.push_back(v1);
            v1.clear();
        }
        return retv;
    }
};

4. 单词接龙

https://leetcode.cn/problems/word-ladder/

在这里插入图片描述

int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
    //hash表的查询效率最高
    unordered_set<string> wordDict(wordList.begin(), wordList.end());
    //标记单词是否已经访问过,访问过的不再访问
    unordered_set<string> visited;
    visited.insert(beginWord);
    //初始化队列
    queue<string> q;
    q.push(beginWord);
    int res = 1;
    while (!q.empty()){
        int nextSize = q.size();
        //每一步都要把队列中上一步添加的所有单词转换一遍
        //最短的转换肯定在这些单词当中, 所有这些词的转换只能算一次转换
        //因为都是上一步转换出来的
        while (nextSize--){
            string curWord = q.front();
            q.pop();
            //尝试转换当前单词的每一个位置
            for (int i = 0; i < curWord.size(); i++){
                string newWord = curWord;
                //每一个位置用26个字母分别替换
                for (auto ch = 'a'; ch <= 'z'; ch++){
                    newWord[i] = ch;
                    //如果列表中没有此单词或者已经访问过(它的转换已经遍历过,无需再次遍历),则跳过
                    if (!wordDict.count(newWord) || visited.count(newWord))
                        continue;
                    //转换成功,则在上一步转换的基础上+1
                    if (newWord == endWord)
                        return res + 1;
                    //还没有转换成功,则新的单词入队
                    visited.insert(newWord);
                    q.push(newWord);
                }
            }
        }
        res++;
    }
    //转换不成功,返回0
    return 0;
    }

5.最小基因变化

https://leetcode.cn/problems/minimum-genetic-mutation/

在这里插入图片描述

class Solution {
public:
    int minMutation(string start, string end, vector<string>& bank) {
        unordered_set<string> bankdict(bank.begin(), bank.end()); //hash查找效率高
        queue<string> q1;
        unordered_set<string> visited;

        q1.push(start);
        visited.insert(start);
        int step=0;
        while(!q1.empty()){
            int size = q1.size();
            for(int i=0;i<size;++i){  //节点扩散
                string cur = q1.front();
                q1.pop();

                if(cur==end) //终点判断
                    return step;

                for(int i=0;i<cur.size();++i){ //新节点入队
                    string tmp = cur;
                    for(int k=0;k<4;++k){
                        tmp[i]=ch[k];
                        if(bankdict.count(tmp) && !visited.count(tmp)){//满足条件入队,并标记
                            q1.push(tmp);
                            visited.insert(tmp);
                        }
                    }
                }
            }
            step++;
        }
        return -1;
    }

private:
    char ch[4]={'A','C','T','G'};
};

6.打开转盘锁

https://leetcode.cn/problems/open-the-lock/

在这里插入图片描述

class Solution {
public:
    int openLock(vector<string>& deadends, string target) {
        unordered_set<string> deadendcict(deadends.begin(),deadends.end()); //hash查找效率高
        queue<string> q1;
        q1.push(string("0000"));
        unordered_set<string>   visited;
        visited.insert(q1.front());

        //特殊情况
        if(deadendcict.count("0000") ||  deadendcict.count(target)) return -1;

        int  step=0;
        while(!q1.empty()){
            int size=q1.size();
            while(size--){
                string cur=q1.front();
                q1.pop();
                for(int i=0;i<cur.size();++i){//遍历下一步可能的选择
                    if(strcmp(target.c_str(),cur.c_str())==0) //终点判断
                        return   step;  

                    for(int k=0;k<3;k=k+2){ 
                        string tmp=cur;
                        tmp[i]=ch[tmp[i]-'0'+k];  //+1或者-1

                        if( !deadendcict.count(tmp) && !visited.count(tmp)){  //死锁表里没有且没访问过
                            visited.insert(tmp);
                            q1.push(tmp);
                        }
                    }
                }
            }
            step++;
        }
        return  -1;
     }
    
private:
    char ch[12]={'9','0','1','2','3','4','5','6','7','8','9','0'};
};

4 5 6这三个题一模一样的套路。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值