【数据结构与算法】搜索算法(深度优先搜索 DFS和广度优先搜索 BFS)以及典型算法例题

目录

  • 搜索算法(深度优先搜索DFS和广度优先搜索BFS)以及典型算法例题
    • 深度优先搜索 (Depth First Search 简称 DFS)
      • DFS 的设计步骤
      • 深度优先搜索(DFS)算法例题
        • 例题一:N皇后问题
        • 例题二:路径之谜问题
        • 例题三:最大数字
    • 广度优先搜索(Breadth First Search 简称 BFS)
      • 广度优先搜索基本概念
      • 广度优先搜索(BFS)算法例题
        • 例题一:长草问题
        • 例题二:走迷宫问题

【数据结构与算法】系列文章链接: 【数据结构与算法】递推法和递归法解题(递归递推算法典型例题)
【数据结构与算法】系列文章链接: 【数据结构与算法】C++的STL模板(迭代器iterator、容器vector、队列queue、集合set、映射map)以及算法例题
【数据结构与算法】系列文章链接: 【数据结构与算法】二分查找算法

搜索算法(深度优先搜索DFS和广度优先搜索BFS)以及典型算法例题

深度优先搜索 (Depth First Search 简称 DFS)

注意:深度优先搜索算法(DFS)时间复杂度较高,深度优先搜索是 O(n!) 的阶乘级算法,它的效率非常低,在数据规模变大时,此算法就难以解决当前的问题了。

DFS 的设计步骤

  1. 确定题目的状态以及边界
  2. 确定状态的转移方式
  3. 找到问题的出口,计数或某个状态
  4. 设计搜索
    DFS的通用模板
int check(这里输入相关参数){
	if(condition)//括号中写上对应的满足条件
		return 1;//满足条件后输出 1 
	return 0;
}
bool pd(输入判断的相关参数){
	//根据题中 进行具体的操作
}

void dfs(int step)
{
        //判断边界pd()
        {
            //不在边界内,即回溯
        }
        //尝试每一种可能
        {
               //满足check条件

               //标记

               //继续下一步
               dfs(step+1)//恢复初始状态(回溯的时候要用到)
        }
}

深度优先搜索(DFS)算法例题

例题一:N皇后问题

在这里插入图片描述
输入示例:

5

输出示例:

10

题目分析:

  1. 第一步:
    设:当前行为第一行,当前列为第一列,从第一列开始搜索,即只能让皇后从第一行放到第n行。
    这样做的好处是,我们不需要去判断皇后是否同行,我们只需要去判断皇后是否在斜线和是否同列就行。
  2. 判断边界
    在当前行,当前列的位置上判断是否满足条件(也就是保证经过这一点的行,列与斜线上都没有两个皇后),如果不满足,跳到第五步(不符合边界条件)
    判断条件为:
    我们使用数值x[a]=i来表示第a个皇后的位置在第a行的第i列。
    判断是否同列的方法是:循环判断x[a]==x[i]是否为真。
    判断是否在同一斜线上的方法:循环判断abs(x[k]-x[i]) == abs(k-i) 是否为真
  3. 搜索过程
    调用check()函数
    如果完成(满足)题意的任务 加一,就继续调用函数 放下一个皇后
  4. check()函数
    如果搜索到第N+1行的时候。求得结果 (可行方案数量)记录加一。
  5. 当前位置不满足,进行回溯。

边界判断函数PD(int k) 判断是否越界:

int PD(int k)//边界判断
{

    for(int i=1; i<k; i++)
    {
        if(abs(k-i)==abs(x[k]-x[i]))
            return 0;
        else if (x[k]==x[i])
            return 0;
        //即判断是否符合条件来放,i表示皇后所在的行数,x[i]表示所在的列数,
        //所以前面那个条件用来判断两个皇后是否在对角线上,后面用来判断是否在同一列上。
        //行数不需要判断,因为他们本身的i就代表的是行数
    }
    return 1;
}

检查是否完成题中任务的函数check(int a)

bool check(int a)
{

    if(a>n)
        sum++;
    else
        return 0;
    return 1;
}

深度优先搜索的函数 DFS(int a)

void DFS(int a)
{
    if(check(a))
        return ;
    else
        for(int i=1; i<=n; i++)
        {
            x[a]=i;
                //第a个皇后放的列数
            if(PD(a))
                    //判断是否能放这步
                DFS(a+1);
                    //能的话进行下一个皇后的放置
            x[a]=i;
            else continue ;
                    //不能就下一列
        }
}

题解代码示例:


#include <iostream>
#include <cstdio>
using namespace std;
int x[15] = {0};//数组稍微建立大一点 防止某些不影响结果的越界报错
int sum,n;//

int PD(int k)//边界判断
{

    for(int i=1; i<k; i++)
    {
        if(abs(k-i)==abs(x[k]-x[i]))
            return 0;
        else if (x[k]==x[i])
            return 0;
        //即判断是否符合条件来放,i表示皇后所在的行数,x[i]表示所在的列数,
        //所以前面那个条件用来判断两个皇后是否在对角线上,后面用来判断是否在同一列上。
        //行数不需要判断,因为他们本身的i就代表的是行数
    }
    return 1;
}

//检查
bool check(int a)
{

    if(a>n)
        sum++;
    else
        return 0;
    return 1;
}

void DFS(int a)
{
    if(check(a))
        return ;
    else
        for(int i=1; i<=n; i++)
        {
            x[a]=i;
                //第a个皇后放的列数
            if(PD(a))
                    //判断是否能放这步
                DFS(a+1);
                    //能的话进行下一个皇后的放置
            x[a]=i;
            else continue ;
                    //不能就下一列
        }
}
int main()
{
    cin>>n;
    //表示几个皇后
    DFS(1);
    //每次都从第一个皇后开始
    cout<<sum<<endl;
    return 0;
}
例题二:路径之谜问题

在这里插入图片描述
输入示例:

4
2 4 3 4
4 3 3 3

输出示例;

0 4 5 1 2 3 7 11 10 9 13 14 15

题目分析:
方法一:采用逆推法,逆向思维,从终点开始走,每走一格拔下来一个箭(采用方法一 判断条件方便)
方法二:走一格射两个箭。

  1. 设当前位置为第一行,当前列为第一列从左上角开始搜索(寻路)。

  2. 判断边界:
    在当前行,当前列的位置上判断是否满足条件,若不满足条件跳到第五步。
    判断条件:
    flag[x][y]==1标记数组已经被走过
    x<1 || x>n || y<1 || y>n分别表示从左侧走出方格、从右侧走出方格、从上出走出方格、从下处走出方格
    col[x]<=0箭用完了
    rol[y]<=0箭用完了

  3. 搜索过程
    调用check()函数。判断是否走到终点,如果走到终点是否完成任务

  4. check()函数:
    如果当搜索到x=n,y=n时,且箭靶上的箭都没了

  5. 在当前位置上不满足条件的情况,进行回溯,并且还原现场。

check()函数:判断是否走到终点,如果走到终点是否完成任务

bool  check(int x, int y) //判断走过的路径的箭靶数是否与目标相同
{
    if(x==n && y==n)//走到了终点 
    {
        for(int i=1; i<=n; i++)
        {//判断每一列是否为零 
            if(col[i]!=0)
            {
                return false;
            }
            //如果箭靶上的数目不为0,根据逆推,我们通过当前路径得不到箭靶上的结果
        }
        for(int i=1; i<=n; i++)
        {//判断每一行是否为零
            if(rol[i]!=0)
            {
                return false;
            }
            //如果箭靶上的数目不为0,根据逆推,我们通过当前路径得不到箭靶上的结果
        }
        //如果都为零了 就说明这条路对了  然后把这条路线输出出来
        for(int i=0; i<res.size(); i++)
        {
            int x=res[i].first;
            //x 轴坐标
            int y=res[i].second;
            //y 轴坐标
            int sum=n*(x-1)+y-1 ;
            // 通过计算的到为题目要求的坐标系
            cout <<sum<< " ";
        }
        
        cout << endl;
        return false;
        // 成功终止
    }
    //没走到终点
    return true; //继续搜索
    //关于终止还是继续我们交给判定即可
}

判断是否超出边界的函数pd()

//边缘判断条件
bool pd(int x2,int y2) //边界判断
{
    if(flag[x2][y2]==1)
        return 0;
    //已被走过,不能再走,超出边界
    else if(x2<1)
        return 0;
    //从左侧走出方格
    else if(x2>n)
        return 0;
    //从右侧走出方格
    else if(y2<1)
        return 0;
    //从上侧走出方格
    else if(y2>n)
        return 0;
    //从下侧走出方格
    
    //剪枝
    else if(col[x2]<=0)
        return 0;
    //没走到右下角,箭用完了
    else if(rol[y2]<=0)
        return 0;
    //没走到右下角,箭用完了
    
    
    else return 1;
    //符合边界条件,可以继续执行搜索
}

#include <bits/stdc++.h>

using namespace std;

struct PII
{
    int first;//x坐标
    int second;//y坐标
};

const int N = 30;
int rol[N];//行 也就是y轴
int col[N];//列 也就是x轴
int n;//格子数 长宽从1到n
bool flag[N][N]; //用来标记是否走过
vector<PII> res;//


//---------图的路径搜索常用方向移动表示-------

int dx[4]= {0,1,-1,0};
int dy[4]= {1,0,0,-1};
//我们做一下约定:
// 两两组合形成上下左右四个方向
//      1------------------> x
//      |
//      |
//      |
//      |
//      |
//      |
//      |
//      ↓
//      y

// dx[0]=0 dy[0]=1 那么代表向下的方向
// dx[1]=1 dy[1]=0 那么代表向右的方向
// dx[2]=-1 dy[0]=0 那么代表向左的方向
// dx[3]=0 dy[1]=-1 那么代表向上的方向

//--------------------------------------------

bool  check(int x, int y) //判断走过的路径的箭靶数是否与目标相同
{
    if(x==n && y==n)//走到了终点 
    {
        for(int i=1; i<=n; i++)
        {//判断每一列是否为零 
            if(col[i]!=0)
            {
                return false;
            }
            //如果箭靶上的数目不为0,根据逆推,我们通过当前路径得不到箭靶上的结果
        }
        for(int i=1; i<=n; i++)
        {//判断每一行是否为零
            if(rol[i]!=0)
            {
                return false;
            }
            //如果箭靶上的数目不为0,根据逆推,我们通过当前路径得不到箭靶上的结果
        }
        //如果都为零了 就说明这条路对了  然后把这条路线输出出来
        for(int i=0; i<res.size(); i++)
        {
            int x=res[i].first;
            //x 轴坐标
            int y=res[i].second;
            //y 轴坐标
            int sum=n*(x-1)+y-1 ;
            // 通过计算的到为题目要求的坐标系
            cout <<sum<< " ";
        }
        
        cout << endl;
        return false;
        // 成功终止
    }
    //没走到终点
    return true; //继续搜索
    //关于终止还是继续我们交给判定即可
}


//边缘判断条件
bool pd(int x2,int y2) //边界判断
{
    if(flag[x2][y2]==1)
        return 0;
    //已被走过,不能再走,超出边界
    else if(x2<1)
        return 0;
    //从左侧走出方格
    else if(x2>n)
        return 0;
    //从右侧走出方格
    else if(y2<1)
        return 0;
    //从上侧走出方格
    else if(y2>n)
        return 0;
    //从下侧走出方格
    
    //剪枝
    else if(col[x2]<=0)
        return 0;
    //没走到右下角,箭用完了
    else if(rol[y2]<=0)
        return 0;
    //没走到右下角,箭用完了
    
    
    else return 1;
    //符合边界条件,可以继续执行搜索
}


void dfs(int x,int y)
{
    if(!check(x,y))
    {
        return ;
        //包含不符合规则的地方,回溯,用于剪枝
    }
    else
    {
        for(int i=0; i<4; i++)
        {
            int xt=dx[i]+x;
            int yt=dy[i]+y;
            if(!pd(xt,yt))
            {
                continue ;
                //不符合要求继续换方向搜索
            }
            else
            {
                //因为要进行位置转移,我们给它起个名字,叫作案现场
                //比如向下移动
                flag[xt][yt]=true;
                col[xt]--;
                rol[yt]--;
                res.push_back({xt,yt});
                dfs(xt,yt);
                //搜索回溯后,因为没有找到正确答案,所以要回复作案现场,返回到搜索之前
                res.pop_back();
                flag[xt][yt]=false;
                col[xt]++;
                rol[yt]++;
            }
        }
    }
}

int main()
{
    cin >> n;
    for(int i=1; i<=n; i++)
        cin >> rol[i];
    for(int i=1; i<=n; i++)
        cin >> col[i];
    flag[1][1]=true;
    col[1]--;//先拔一根箭
    rol[1]--;//先拔一根箭
    res.push_back({1,1});
    dfs(1,1);
    return 0;
}
例题三:最大数字

在这里插入图片描述
输入样例:

123 1 2

输出样例:

933

在这里插入图片描述
题目分析:

从左到右以此判断,从左边开始枚举。处理的时候的目的就是保证当前正在处理的数尽可能的变大
使用的时候对于一个数要么使用方法一,要么使用方法二,因为它们是抵消的效果。
对于一个数字:
**操作二的使用情况:**如果这个数大于m(操作二的最大执行次数),那么就没必要执行操作二了,这样反而让这个数据更小。因此执行操作二的条件是:x<m.
**操作一的使用情况:**如果这个数据x>=m我们就执行操作一,一直加尽量加到9,那么需要进行 9-x 次 操作一。当然可能此时 1 号操作并不足以让我们将 x 变成 9,但我们还是使用剩余的全部的次数将其变大,也就是变为x+t。因此,本次使用了操作一的次数为t=min(n,9-x).

题解代码示例:

#include<iostream>
#include<vector>
using namespace std;
typedef long long LL;

char c[20];
LL ans=0;

//n:1号操作剩余次数  m:2号操作剩余次数
int n,m;
void dfs(int i,LL v){
	//从左往右	 
    int x=c[i]-'0';//数据转化 
    
    if(c[i]){//检查 c[i] 是否存在且不为空字符 
    	
        //应该使用的操作次数
        int t=min(n,9-x);
        n-=t;
        dfs(i+1,v*10+x+t);//递归调用
        //回溯
        n+=t;
        
        //考虑操作2是否能够使用
        //目的是减小到9 
        if(m>x){//只有在m>x 的情况下才使用
            m-=(x+1);
            dfs(i+1,v*10+9);//递归调用
            //回溯
            m+=(x+1);
        }
        
    }
    
	else{
        //答案取max
        ans=max(ans,v);
    }
}
int main()
{
    scanf("%s%d%d",c,&n,&m);
    dfs(0,0);
    printf("%lld\n",ans);
    return 0;
}

方法二:(方法二存在样例不通过的情况 )

#include<iostream>
#include<vector>
using namespace std;
typedef long long LL;

char c[20];
LL ans=0;

//n:1号操作剩余次数  m:2号操作剩余次数
int n,m;
void find_max(int i,LL v){
	//从左往右	 
    int x;//数据转化 
    int t;
    //用的是字符串 '\0' 
    while(c[i]){//检查 c[i] 是否存在且不为空字符 
    	x=c[i]-'0';//转换数字
		 
    	if(m<=x){//如果这个数 大于或等于 减一的操作次数  
        
			//应该使用的操作次数
        	t=min(n,9-x);//
        	n-=t;
        	v=v*10+x+t;//记录下来 x+t 加完后的数 
        	i++;
        	ans=max(ans,v);
    	}
        //考虑操作2是否能够使用
        //目的是减小到9 
        else{
        	v=v*10+9;
            m-=(x+1);
            i++;
            ans=max(ans,v);
	    }
	}
	
    
}
int main()
{
    scanf("%s%d%d",c,&n,&m);
    find_max(0,0);
    printf("%lld\n",ans);
    return 0;
}

广度优先搜索(Breadth First Search 简称 BFS)

广度优先搜索(Breadth First Search,简称BFS):从某个状态开始,将所有节点加入一个先进先出的队列,然后一层层进行状态转移,并且展开节点。

广度优先搜索基本概念

伪代码:

int check(参数)
{
    if(满足条件)
        return 1;
    return 0;
}
bool pd(参数){
    相应操作
}
void bfs()
{
    1. 把根节点放入队列尾端
    2. 每次从队列中取出一个节点
    3. Check 判断是不是答案,如果是结束算法 return;
    4. 把当前取出的节点扩展,如果扩展后的节点经Pd()后符合要求,就放入队列,不符合就不放。
    5. 转到步骤2,循环执行
}

如果所有节点被扩展完了,没有找到答案就无解。

广度优先搜索(BFS)算法例题

例题一:长草问题

在这里插入图片描述

输入示例:

4 5
.g...
.....
..g..
.....
2

输出示例:

gggg.
gggg.
ggggg
.ggg.

解题思路:使用 N × M N×M N×M 的矩阵来表示草地。

  1. 将字母g的位置加入队列
  2. 判断边界:
    判断是否长草,是否超出范围
  3. 搜索
    不断从队列中取出一个节点,进行上下左右的扩展,执行2的判断边界条件,符合的就放入队列,不符合就跳过。
    执行K次扩展,输出草地状态
  4. check()函数:
    本题输出最终状态 因此不用这个函数

在广度优先搜索(BFS)中,我们通常需要对队列中的节点进行扩展,也就是对当前节点的邻居节点进行处理。处理完一个节点后,我们应该将其从队列中移除,以避免重复处理相同的节点,确保每个节点只被处理一次。
因此需要:

	tempPair = q.front();
    q.pop();
    //这两步是取出队首的节点

题解代码示例:



#include <bits/stdc++.h>
using namespace std;
const int M = 1005;

struct PII//坐标
{
    int first;
    int second;
};

// C++ 有个数据类型叫 pair 上面的就可以定义为 pair<int,int> 用起来比较方便。
PII tempPair;//临时结点

char Map[M][M];

//---------图的路径搜索常用方向移动表示-------
int dx[4]= {0,1,-1,0};
int dy[4]= {1,0,0,-1};
// 两两组合形成上下左右四个方向
//      1------------------> x
//      |
//      |
//      |
//      |
//      |
//      |
//      |
//      ↓
//      y

// dx[0]=0 dy[0]=1 那么代表向下的方向

// dx[1]=1 dy[1]=0 那么代表向右的方向

// dx[2]=-1 dy[0]=0 那么代表向左的方向

// dx[3]=0 dy[1]=-1 那么代表向上的方向

int n;// n 行
int m;// m 列
int k;// k 次

//记录 坐标位置
queue<PII > q; //广度优先搜索所用的队列

int len;//记录节点数量方便后续k的计算

bool pd(int x, int y)
{
    if(x<1)
        return 0;
    // /x 轴坐标 左侧越界
    else if(x>n)
        return 0;
    //x 轴坐标 右侧越界
    else  if(y<1)
        return 0;
    //y 轴坐标 上侧越界
    else if(y>m)
        return 0;
    //y 轴坐标 下侧越界
    else if(Map[x][y]=='g')
        return 0;
    //已经长草了
    else return 1;
    // 在范围内,且没长草
}

void BFS()
{
    //BFS 
    //记得 层次
    while(!q.empty()&&k>0)
    {
        tempPair = q.front();
        q.pop();
        //这两步是取出队首的节点

        int x = tempPair.first;//横坐标
        int y = tempPair.second;//纵坐标
        //四种扩展情况
        for(int i=0; i<4; i++)
        {
            int nowx = x+dx[i]; //扩展后的横坐标
            int nowy = y+dy[i]; //扩展后的纵坐标

            if(pd(nowx,nowy))
            {
                q.push({nowx,nowy});
                Map[nowx][nowy]='g';
            }
            //符合要求执行扩展,不符合要求,忽略即可。
        }

        len--; //每扩展一个节点len  -1

        if(len==0)
        {
            //当len =0 时,代表当前层扩展完了,那么就代表第一个月扩展完了
            k--; // 所以k--
            //更新草的数目
            len = q.size(); // 当前层扩展完了,那就该扩展下一层了,所以len又被赋值为下一层的节点数目的值
        }
    }
}

int main()
{
    //输入
    cin>>n>>m;
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=m; j++)
        {
            cin>>Map[i][j];
            if(Map[i][j]=='g')
            {
                tempPair.first=i;
                tempPair.second=j;
               // cout<<i<<""<<j<<endl;
                q.push(tempPair);//将初始有树的结点加入队列
            }
        }
    }

    len = q.size();//记录第一层的节点数量方便后续k的计算
    cin>>k;
    BFS();

    //输出
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=m; j++)
        {
            cout<<Map[i][j];
        }

        cout<<endl;
    }
    return 0;
}
例题二:走迷宫问题

在这里插入图片描述
输入示例:

5 5
1 0 1 1 0
1 1 0 1 1
0 1 0 1 1
1 1 1 1 1
1 0 0 0 1
1 1 5 5

输出示例:

8

解题分析:

1. 开始BFS,将入口加入队列中。
2. 判断边界:

题解代码示例:


#include <bits/stdc++.h>
using namespace std;

int vis[150][150]; //用于存储是否访问过,并且存储长度

char G[150][150]; //用于存储题目给出的地图

int n,m,ans=0;

int dx[4] = {0,0,-1,1};

int dy[4] = {1,-1,0,0};

//上下左右移动

struct node
{
    int x;
    int y;
};

node Start,End;
bool pd(int x,int y)
{


    if(x<1)
        return 0;
    //从左侧走出方格

    else if(x>n)
        return 0;
    //从右侧走出方格

    else if(y<1)
        return 0;
    //从上侧走出方格

    else if(y>m)
        return 0;
    //从下侧走出方格

    else if( vis[x][y]!=0)
        //已经访问了
        return 0;
    else if(G[x][y]!='1') return 0;
    //不是路不能走
    else return 1;
}

bool  check(int x, int y)
{

    if(x == End.x&& y == End.y)   //找到终点,把距离给他
    {
        ans  =  vis[x][ y];
        return 1;
    }

    else    return 0;

}
void bfs()
{
    queue<node>q;

    node now,next;

    q.push(Start);     //将起点压人队列中

    vis[Start.x][Start.y] = 1;

    while(!q.empty())
    {
        now = q.front();

        if(check(now.x,now.y))
            return ;

        q.pop();     //将队列最前面的弹出。

        for(int i=0; i<4; i++)  //四个方向
        {

            int nextx = now.x + dx[i];
            int nexty = now.y + dy[i];

            if(pd(nextx,nexty))  //判断是否符合条件
            {

                next.x=nextx;
                next.y=nexty;

                q.push(next);

                vis[nextx][nexty] = vis[now.x][now.y]+1; //步数+1
            }
        }
    }
}
int main()
{
    cin>>n>>m;
    //memset(vis,0,sizeof(vis));
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=m; j++)
        {
            cin>>G[i][j];
        }
    }

    cin>>Start.x>>Start.y>>End.x>>End.y;

    ans = 0;

    bfs();
    cout<<ans-1<<endl;

    return 0;
}

感谢您的阅读!!!
【数据结构与算法】系列文章链接: 【数据结构与算法】递推法和递归法解题(递归递推算法典型例题)
【数据结构与算法】系列文章链接: 【数据结构与算法】C++的STL模板(迭代器iterator、容器vector、队列queue、集合set、映射map)以及算法例题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/543773.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

FreeRTOS学习 -- FreeRTOSConfig.h介绍

一、FreeRTOSConfig.h文件 FreeRTOS 的系统配置文件为 FreeRTOSConfig.h&#xff0c;在此配置文件中可以完成 FreeRTOS 的裁剪和配置。 FreeRTOS 的配置基本是通过在 FreeRTOSConfig.h 中使用“#define”这样的语句来定义宏定义实现的。在 FreeRTOS 的官方 demo 中&#xff0…

CentOS7离线升级OpenSSH_8.8p1

一、环境 centos7.9,升级openssh到8.8p1最新版本 二、下载升级包 # openssl和zlib为相关依赖 wget https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-8.8p1.tar.gz wget https://www.openssl.org/source/openssl-1.1.1j.tar.gz wget http://www.zlib.net/zl…

mysql dll文件的缺失和Can‘t connect to MySQL server on ‘localhost‘ (10061)

个人笔记&#xff08;整理不易&#xff0c;有帮助&#xff0c;收藏点赞评论&#xff0c;爱你们&#xff01;&#xff01;&#xff01;你的支持是我写作的动力&#xff09; 笔记目录&#xff1a;学习笔记目录_pytest和unittest、airtest_weixin_42717928的博客-CSDN博客 个人随笔…

数学:人工智能学习之路上的“拦路虎”及其背后的奥秘

在人工智能的浪潮席卷全球的今天&#xff0c;越来越多的人开始涉足这一领域&#xff0c;以期掌握其核心技术&#xff0c;为未来的科技发展贡献力量。然而&#xff0c;在学习的道路上&#xff0c;许多人却遇到了一个不小的挑战——数学。为何数学会成为学习人工智能的“拦路虎”…

js学习总结

这里写目录标题 前情提要JavaScript书写位置1. 内部javaScript (不常用)2. 外部javaScript (常用)3.内联javaScript (常用) js中的输入和输出输出语法1. document.write()2. alert()3. console.log() 输入语法prompt() 前情提要 1. 在javaScript中的 分号 是可以省略的JavaScr…

rocketmq面试

broker主从复制机制 同步复制&#xff1a; 等Master和Slave均写成功后&#xff0c;才反馈给客户端写成功状态&#xff1b; 如果Master出故障&#xff0c; Slave上有全部的备份数据&#xff0c;容易恢复&#xff0c;但是同步复制会增大数据写入延迟&#xff0c;降低系统吞吐量。…

SMS垃圾短信识别项目

注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 项目背景 随着数字通信的快速发展&#xff0c;垃圾短信成为了一个普遍而烦人的问题。这些不请自来的消息不仅打扰了我们的日常生活&#xff0c;…

视频基础学习六——视频编码基础三(h264框架配合图文+具体抓包分析 万字)

系列文章目录 视频基础学习一——色立体、三原色以及像素 视频基础学习二——图像深度与格式&#xff08;RGB与YUV&#xff09; 视频基础学习三——视频帧率、码率与分辨率 视频基础学习四——视频编码基础一&#xff08;冗余信息&#xff09; 视频基础学习五——视频编码基础…

Redis漏洞利用

未授权 可以利用超级弱口令工具来判断redis是否能未授权登录 telnet #尝试登录info #查看redis信息 RCE方法 写shell 需要写权限需要知道web网站路径 config set dir /var/www/html config set dbfilename redis.php set test "<?php phpinfo(); ?>" sa…

低成本,高效能:探索物联网新宠LoRa

LoRa是什么&#xff1f; LoRa是一种物联网无线传输技术&#xff0c;利用调制解调器实现低功耗远距离数据传输。其基本工作原理是通过基站发送数据到特定终端设备&#xff0c;实现双向数据传输。 LoRa无线传输技术是一种为低功耗和低成本设计的无线技术&#xff0c;用于实现远距…

mybatis的使用技巧7——mysql中in,exists,join的用法和区别

在实际项目开发中&#xff0c;sql查询中的连表查询和子查询用的是最多的&#xff0c;但是很多人对于in&#xff0c;exists&#xff0c;join的用法认识不足&#xff0c;随意运用&#xff0c;这种情况如果在大数据量查询时&#xff0c;会存在很大的隐患。 一.子查询&#xff08;…

transformer入门知识解析——新手必看

对应课程&#xff1a;Transformer简明教程, 从理论到代码实现到项目实战, NLP进阶必知必会._哔哩哔哩_bilibili 1.初识transformer结构 transformer的结构&#xff1a; 编码器解码器的内部结构&#xff1a; Self Attention 表示自注意力机制 Feed Forward 表示全连接层 2.计算…

45.HarmonyOS鸿蒙系统 App(ArkUI)创建列表(List)

列表是一种复杂的容器&#xff0c;当列表项达到一定数量&#xff0c;内容超过屏幕大小时&#xff0c;可以自动提供滚动功能。它适合用于呈现同类数据类型或数据类型集&#xff0c;例如图片和文本。在列表中显示数据集合是许多应用程序中的常见要求&#xff08;如通讯录、音乐列…

springBoot+vue编程中使用mybatis-plus遇到的问题

mybatis-plus中遇到的问题Code Companion Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)…

如何正确使用数字化仪前端信号调理?(一)

一、前言 板卡式的数字转换器和类似测量仪器&#xff0c;比如图1所示的德思特TS-M4i系列&#xff0c;都需要为各种各样的特性信号与内部模数转换器&#xff08;ADC&#xff09;的固定输入范围做匹配。 图1&#xff1a;德思特TS-M4i系列高速数字化仪&#xff0c;包括2或4通道版…

大模型项目整体规划、技术选型和案例分析经验分享

1 项目整体规划 1.1 明确场景 toB or toC&#xff08;面向企业还是面向消费者&#xff09; toB&#xff08;面向企业&#xff09;&#xff1a;指的是产品或服务主要面向其他企业或组织。这类产品通常需要解决特定的商业问题&#xff0c;强调效率和集成性&#xff0c;并且可能需…

机器学习-随机森林温度预测模型优化

文章目录 前言旧模型训练新模型训练参数查看组合参数训练学习模型评估 前言 在机器学习-随机森林算法预测温度一文中&#xff0c;通过增大模型训练数据集和训练特征的方式去优化模型的性能&#xff0c;本文将记录第三方种优化方式&#xff0c;通过调整随机森林创建模型参数的方…

10.哀家要长脑子了!

1. 704. 二分查找 - 力扣&#xff08;LeetCode&#xff09; 哎哟 我去 我还以为你都搞懂了 呵呵 当时问题出现在右边界初始化 左闭右开 右边界是取不到的 int left 0, right nums.size() ; while(left < right) { int mid left (right - left) / 2; if( target > …

数据可视化高级技术Echarts(堆叠柱状图)

目录 一.如何实现 二.代码展示 1.stack名称相同&#xff08;直接堆叠&#xff09; 2. stack名称不相同&#xff08;相同的堆叠&#xff0c;不同的新生成一列&#xff09; 一.如何实现 数据堆叠&#xff0c;同个类目轴上系列配置相同的 stack 值可以堆叠放置。即在series中…

前端三件套学习笔记(持更)

目录 1、HTML,CSS,JS区别 2、HTML结构 1、HTML,CSS,JS区别 结构写到 HTML 文件中&#xff0c; 表现写到 CSS 文件中&#xff0c; 行为写到 JavaScript文件中。 2、HTML结构 <!DOCTYPE html> <html><head><title>我的第一个页面</title><…