队列与BFS的常见做法

本文介绍了如何运用广度优先搜索(BFS)算法来寻找图中最短路径。通过创建bool数组记录节点状态,使用队列进行层次遍历,更新节点路径长度。分别展示了在不同场景下,如计算房间中最短路径、解锁转盘锁及01矩阵中距离最近0的计算等应用。在实现过程中,队列的数据类型根据问题需求可选择List<int>或List<string>。文章强调了BFS在处理最短路径问题时的有效性和灵活性。
摘要由CSDN通过智能技术生成

广度优先搜索(BFS)的一个常见应用是找出从根结点到目标结点的最短路径。队列非常适合用来处理标准的BFS。

以计算最短路径为例,BFS通常有以下步骤:

  1. 创建一个合适大小的bool数组或哈希表来记录节点是否被遍历过,初始时将所有所有位置置为false;
  2. 创建队列,注意队列的数据类型
  3. 确定起点,并将起点入队,将起点对应位置置为true,路径长度level=1
  4. 当队列不为空时并且没有到达终点时循环以下步骤
  5. 将当前队列长度记为count,出队所有count个元素
  6. 每出队一个节点,依次判断它周围的点是否符合条件
  7. 若符合则入队将相应位置置为true
  8. level+1,返回第三步

第6步中的条件可能有几种:

  • 数组边界条件,0<=x<length
  • 是否被遍历过
  • 是否是可行的路径
  • 如果节点记录了路径长度,原路径是否已经短于现路径

第5步是如果必须严格按照层次遍历时必须执行的,count记录了本层的元素数量

注意第4步,并不是所有问题都有终点,没有终点时条件仅为队列不空

墙与门

 本题就没有严格遵照以上的第四步,因为每个节点都已经记录了当前最短的路径长度,不需知道当前的层次数,只要比前一层大1就可以了。循环条件也没有终点。

本题队列中的数据是坐标,所以队列数据类型是List<int>

public class Solution {
    public void WallsAndGates(int[][] rooms) {
        List<List<int>> door=new List<List<int>>();
        for(int i=0;i<rooms.Length;i++)
        for(int j=0;j<rooms[0].Length;j++)
        {
            if(rooms[i][j]==0)
            {
                List<int> temp=new List<int>();
                temp.Add(i);
                temp.Add(j);
                door.Add(temp);
            }
        }//得到所有门的坐标
        bool[,] gone=new bool[rooms.Length,rooms[0].Length];
        for(int a=0;a<door.Count;a++)//几个门循环几次
        {
            for(int i=0;i<rooms.Length;i++)
            for(int j=0;j<rooms[0].Length;j++)
            gone[i,j]=false;
            Queue<List<int>> q=new Queue<List<int>>();
            q.Enqueue(door[a]);gone[door[a][0],door[a][1]]=true;
            while(q.Count!=0)
            {
                List<int> index=new List<int>();
                index=q.Dequeue();
                if(index[0]-1>=0&&!gone[index[0]-1,index[1]]&&rooms[index[0]-1][index[1]]!=-1
                &&rooms[index[0]][index[1]]+1<rooms[index[0]-1][index[1]])
                {
                    rooms[index[0]-1][index[1]]=rooms[index[0]][index[1]]+1;
                    List<int> temp=new List<int>();
                    temp.Add(index[0]-1);temp.Add(index[1]);
                    gone[index[0]-1,index[1]]=true;
                    q.Enqueue(temp);
                }
                if(index[0]+1<rooms.Length&&!gone[index[0]+1,index[1]]
                &&rooms[index[0]+1][index[1]]!=-1
                &&rooms[index[0]][index[1]]+1<rooms[index[0]+1][index[1]])
                {
                    rooms[index[0]+1][index[1]]=rooms[index[0]][index[1]]+1;
                    List<int> temp=new List<int>();
                    temp.Add(index[0]+1);temp.Add(index[1]);
                    gone[index[0]+1,index[1]]=true;
                    q.Enqueue(temp);
                }
                if(index[1]-1>=0&&!gone[index[0],index[1]-1]
                &&rooms[index[0]][index[1]-1]!=-1
                &&rooms[index[0]][index[1]]+1<rooms[index[0]][index[1]-1])
                {
                    rooms[index[0]][index[1]-1]=rooms[index[0]][index[1]]+1;
                    List<int> temp=new List<int>();
                    temp.Add(index[0]);temp.Add(index[1]-1);
                    gone[index[0],index[1]-1]=true;
                    q.Enqueue(temp);
                }
                if(index[1]+1<rooms[0].Length&&!gone[index[0],index[1]+1]
                &&rooms[index[0]][index[1]+1]!=-1
                &&rooms[index[0]][index[1]]+1<rooms[index[0]][index[1]+1])
                {
                    rooms[index[0]][index[1]+1]=rooms[index[0]][index[1]]+1;
                    List<int> temp=new List<int>();
                    temp.Add(index[0]);temp.Add(index[1]+1);
                    gone[index[0],index[1]+1]=true;
                    q.Enqueue(temp);
                }
            }
        }
        return;
    }
}

打开转盘锁

这道题实际上就是一个四维图中的最短路径,处理bool数组时把字符串转化为数字比较方便。

C#中字符+数字得到的相应ASCII码值,如'0'+1=49,再进行强制转换可以得到相应字符,

如(char)('0'+1)='1'

本题队列中的数据是字符串,不过为了处理数据的方便,所以队列数据类型是List<string>

public class Solution {
    public int OpenLock(string[] deadends, string target) {
        Queue<List<string>> q=new Queue<List<string>>();
        int num=0;bool arrive=false;
        bool[] gone=new bool[10000];
        for(int i=0;i<10000;i++)
        gone[i]=false;
        string start="0000";
        if(indead(deadends,start))
        return -1;
        List<string> s=new List<string>();
        s.Add(start);q.Enqueue(s);
        while(q.Count!=0&&!arrive)
        {
            num++;int count=q.Count;
            for(int i=0;i<count;i++)
            {
                List<string> temp=new List<string>();
                temp=q.Dequeue();
                for(int j=0;j<temp.Count;j++)
                {
                    if(temp[j]!=target)
                    q.Enqueue(rotate(deadends,temp[j],gone));
                    else
                    {arrive=true;break;}
                }
                if(arrive)
                break;
            }
        }
        if(arrive)
        return num-1;
        else
        return -1;
    }
    public List<string> rotate(string[] deadends,string initial,bool[] gone)
    {
        List<string> res=new List<string>();
        for(int i=0;i<4;i++)
        {
            string temp="";
            for(int j=0;j<4;j++)
            {
                if(j!=i)
                temp+=initial[j];
                else
                {
                if(initial[i]<'9')
                temp+=(char)(initial[i]+1);
                else
                temp+='0';
                }
            }
            if(!gone[Convert.ToInt32(temp)]&&!indead(deadends,temp))
            {
                res.Add(temp);
                gone[Convert.ToInt32(temp)]=true;
            }
            temp="";
            for(int j=0;j<4;j++)
            {
                if(j!=i)
                temp+=initial[j];
                else
                {
                if(initial[i]>'0')
                temp+=(char)(initial[i]-1);
                else
                temp+='9';
                }
            }
            if(!gone[Convert.ToInt32(temp)]&&!indead(deadends,temp))
            {
                res.Add(temp);
                gone[Convert.ToInt32(temp)]=true;
            }
        }
        return res;
    }
    public bool indead(string[] deadends,string str)
    {
        for(int i=0;i<deadends.Length;i++)
        if(deadends[i]==str)
        return true;
        return false;
    }
}

01 矩阵

给定一个由 0 和 1 组成的矩阵 mat ,请输出一个大小相同的矩阵,其中每一个格子是 mat 中对应位置元素到最近的 0 的距离。两个相邻元素间的距离为 1 。

 首先确定起点,看起来0是不用改变,似乎可以从1开始,但是1还分为与0相邻和不相邻两种,其中实际可能有多层,所以起点应该是0结点。

队列中的数据是坐标,所以队列数据类型为List<int>

因为路径长度严格等于层次数,所以,每次出队必须出队所有元素。

public class Solution {
    public int[][] UpdateMatrix(int[][] mat) {
        bool[,] gone=new bool[mat.Length,mat[0].Length];
        Queue<List<int>> q=new Queue<List<int>>();
        for(int i=0;i<mat.Length;i++)
        for(int j=0;j<mat[0].Length;j++)
        {
            if(mat[i][j]==0)
            {
                List<int> index=new List<int>();
                index.Add(i);index.Add(j);
                q.Enqueue(index);
                gone[i,j]=true;
            }
            else
            gone[i,j]=false;
        }
        int level=1;
        while(q.Count!=0)
        {
            int count=q.Count;
            for(int i=0;i<count;i++)
            {
                List<int> index=new List<int>();
                index=q.Dequeue();
                if(index[0]-1>=0&&!gone[index[0]-1,index[1]])
                {
                    List<int> temp=new List<int>();
                    temp.Add(index[0]-1);temp.Add(index[1]);
                    gone[temp[0],temp[1]]=true;
                    mat[temp[0]][temp[1]]=level;
                    q.Enqueue(temp);
                }
                if(index[0]+1<mat.Length&&!gone[index[0]+1,index[1]])
                {
                    List<int> temp=new List<int>();
                    temp.Add(index[0]+1);temp.Add(index[1]);
                    gone[temp[0],temp[1]]=true;
                    mat[temp[0]][temp[1]]=level;
                    q.Enqueue(temp);
                }
                if(index[1]-1>=0&&!gone[index[0],index[1]-1])
                {
                    List<int> temp=new List<int>();
                    temp.Add(index[0]);temp.Add(index[1]-1);
                    gone[temp[0],temp[1]]=true;
                    mat[temp[0]][temp[1]]=level;
                    q.Enqueue(temp);
                }
                if(index[1]+1<mat[0].Length&&!gone[index[0],index[1]+1])
                {
                    List<int> temp=new List<int>();
                    temp.Add(index[0]);temp.Add(index[1]+1);
                    gone[temp[0],temp[1]]=true;
                    mat[temp[0]][temp[1]]=level;
                    q.Enqueue(temp);
                }
            }
            level++;
        }
        return mat;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值