2021-09-14 leetcode数据结构 队列与广度优先搜索BFS 200.岛屿数量 279.完全平方数 752.打开转盘锁 c++

广度优先搜索(Breadth-First-Search)

广度优先搜索(BFS):是一种遍历或搜索数据结构(如树或图)的算法。

广度优先搜索与队列

用示例来解释:

Q:A-G 的最短路径?
请添加图片描述
在遍历当前节点时,将其子节点添入队列
Round1: A -> B,C,D //遍历结点A,向队列中添加结点B,C,D
Round2:B,C,D ->E,F,G
Round3:E,F,G ->G(visited) //本该添加F的子结点G,但G在上一轮中已添加过

BFS是一层层进行的,遍历数的结点。彻底地搜索整张图,直到找到结果

实例

leetcode 200.岛屿数量

请添加图片描述

要素

(1)为岛屿的判断标准: 陆地(1)上下左右是否被水(0)包围
(2)岛屿的数量 == 整个联通陆地(1)的数量

采取BFS解决思路

key:从初始岛屿出发向上下左右元素访问,被访问元素中若A为岛屿(1),再访问A的上下左右元素。重复以上

step1:找到为(1)的初始岛屿,先将其入队,再利用FIFO性质取出该元素坐标
step2:对该元素坐标的上下左右进行访问,对被访问元素e进行分类讨论
1)e未被访问,将其坐标入队等待访问
2)e已被访问,跳过

重复step1,2直至队列为空,说明元素周围没有陆地,便可看作岛屿。岛屿的数量就等于队列为空的遍历次数。

AC代码如下

class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        //空输入
        if(grid.empty())
            return 0;
        //行列初始化
        int row = grid.size();
        int col = grid[0].size();
        //定义方向
        int dx[4] = {-1,0,1,0};//行方向
        int dy[4] = {0,1,0,-1};//列方向
        //定义岛屿数量
        int cnt = 0;
        //定义访问记录
        vector<vector<bool>> visited(row, vector<bool>(col,false));//初始都为未访问
        queue<pair<int, int>>que;// 定义队列,队列每个元素存放的是一个坐标
        //main part
        for(int i = 0; i < row; i++){
            for(int j = 0; j < col; j++){//遍历直至出现初始陆地
                if(grid[i][j] == '1' && visited[i][j] == false)//找到未被访问的初始陆地
                    {
                        que.push(make_pair(i,j));
                        cnt++;
                        visited[i][j] = true;//标记访问
                        while(!que.empty()){
                            int x = que.front().first;//获得行坐标
                            int y = que.front().second;//获得列坐标
                            que.pop();//获得坐标后出队
                            for(int k = 0; k < 4; k++){//获得上下左右的信息
                                int xx = x + dx[k];
                                int yy = y + dy[k];
                                //先满足最基本条件:在grid区域内
                                if(xx >=0 && xx < row && yy >=0 && yy < col){
                                //若该元素未被访问且是陆地
                                    if(visited[xx][yy] == false && grid[xx][yy] == '1'){
                                    visited[xx][yy] = true;//标记访问
                                    que.push(make_pair(xx,yy));//入队,等待访问
                                    } 
                                }
                            }
                        }
                    }
            }
        }
        return cnt;
    }
};

leetcode 279. 完全平方数

请添加图片描述

请添加图片描述

要素

(1)重复n= n-i*i直至n=0,i每次从1开始增大
(2)完全平方数之和最少 == n —>0 路径最短

采取BFS解决思路

step1:创建square数组(代码中是从大到小的顺序以减少时间)
step2:对square的元素遍历,对num-i的结果分类讨论
1)num-i == 0,找到最短路径,当前树的高度==完全平方数最少数量
2)num-i > 0,未找到最短路径,将树延伸下去,将下一层树的一个叶子存入队列,等待下一次的判断

AC代码如下

class Solution {
public:
    int numSquares(int n) {
    //step1 创建square数组
        vector<int> square;
        for(int i = 1; i*i <= n; i++)//
            square.insert(square.begin(), i*i);//从大到小存入i*i
        queue<pair<int,int>> que;//分别对应当前num值和树的高度
        que.push(make_pair(n, 1));//树的高度至少为1
        while(1){
            int num = que.front().first;//取出num
            int len = que.front().second;//取出树的高度
            que.pop();//出队
            for(auto i : square){//遍历数组square中的值
                if(i == num)//找到最短路径
                    return len; //返回当前树的高度
                if(i < num)//继续延伸树,再向下找
                    que.push(make_pair(num-i, len+1));//进行树的延伸,树的高度加1
            }
        }
    }
};

PS:

for(int i = 1; i*i <= n; i++)
	square.insert(square.begin(), i*i);

ps 关于insert用法

#include <bits/stdc++.h>
using namespace std;
 
int main()
{
    string str("All that exists is what's ahead.");
    string a, b;
    a = str.insert(4,"sky");
    //在下标为4的位置,插入字符串sky
    cout << a << endl; //输出All skythat exists is what's ahead.
 
    str = "All that exists is what's ahead.";
    b = str.insert(4,5,'x');
    //在下标为4的位置,插入字符串5个字符x
    cout << b << endl; //输出 All xxxxxthat exists is what's ahead.
    return 0;
}

leetcode 752.打开转盘锁

请添加图片描述

要素

注释:s:结点数字 ; deadends:死亡数字
(1)s不能存在deadends包含数字
(2)每次只能变化一个数字且只能变化一位

采取BFS解决思路

将初始字符0000每一位数字+1/-1,得到8个结果,将8个结果的每一位数字分别再进行上述操作。可发现是树
请添加图片描述
对于操作后得到的数字结果:
i) 与之前的结果重复 ->跳过(否则出现死循环)
ii)包含在deadends内 ->跳过(题意要求)
iii)得到新的一串数字 ->继续每位数字+1/-1的操作(延伸树)

用visited来跳过i)和ii)的结果,这里涉及新知识点map(可以更快地检索)

AC代码如下

class Solution {
public:
    int openLock(vector<string>& deadends, string target) {
        unordered_map<string,int> visited;
        for(auto i : deadends)//将deadends中的数字存入visited。标记为已访问
            visited[i] = 1;
        if(visited["0000"] == 1)//若初始数字在deadends中,则返回-1
            return -1;
        queue<string> que;
        int cnt = 0;
        que.push("0000");
        while(!que.empty()){
            int n = que.size();//获得这层树的叶数,以对每个结点进行操作
            while(n--){//遍历该层所有结点
                string s = que.front();
                que.pop();
                if(s == target)//若此时有结点==target,返回树的高度
                    return cnt;
                if(visited[s] != 1){//必须满足未访问
                    visited[s] = 1;//标记访问
                    for(int i = 0; i < 4; i++){
                        string s_1 = s;//进行+1操作的字符串
                        string s_2 = s;//进行-1操作的字符串
                        s_1[i] = s_1[i] == '9' ? '0' : s_1[i]+1;//若该数字为9则+1变为0
                        s_2[i] = s_2[i] == '0' ? '9' : s_2[i]-1;//若该数字为0则-1变9
                        //对未访问的数字加入队列等待访问
                        if(visited[s_1] != 1)
                            que.push(s_1);
                        if(visited[s_2] != 1)
                            que.push(s_2);
                }
               }
            }
            cnt++;
        } 
        return -1;   
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

聪明的Levi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值