LeetCode广搜深搜专题

一、岛屿最大的面积(dfs)

在这里插入图片描述
在这里插入图片描述
这题是可以被一步捕获的棋子数的升级版,“可以被一步捕获的棋子数”只是从一个点开始遍历,而本题把所有的点都作为起始点遍历

  • 深度优先遍历,选定一个点后不断地从上下左右四个方向遍历,直到某个方向碰到0或越界则返回
  • 将已经遍历的点置为0,后面再递归遍历时就不会将此点重复计数
int visit(vector<vector<int>>& grid, int init_x, int init_y){
    
    
	 //这里判断时要注意,一定先判断是否越界,再判断值是否为0,否则报错看不出来,我就找了好长时间。。。
     if(init_x<0 || init_y<0 ||  init_x > grid.size()-1  || init_y > grid[0].size()-1 || grid[init_x][init_y]==0 ){
    
    
         return 0;
     }
     int count = 1;
     grid[init_x][init_y] = 0;//将当前访问的区域置0
     int x_d[4] = {
    
    0, 0, -1, 1};//这里用数组比用vector快
     int y_d[4] = {
    
    1, -1, 0, 0};
     for(int d = 0; d < 4; d++){
    
    //开始往4个方向遍历,直到碰到0或越界
         count += visit(grid, init_x + x_d[d], init_y + y_d[d]);
     }
     return count;
 }

int maxAreaOfIsland(vector<vector<int>>& grid) {
    
    
    int res = 0;
    for(int i=0; i<grid.size(); i++){
    
    
        for(int j=0; j<grid[0].size(); j++){
    
    
            int temp = visit(grid, i, j);//每个点都作为初始点,开始遍历
            res = max(res , temp);
        }
    }
    return res;
}

在这里插入图片描述

二、腐烂的橘子(bfs)


在这里插入图片描述
主要思路:

  • 遍历二维数组,将已经腐烂的橘子的位置入队列
  • 不断地从队列中取出橘子,分别试探上下左右四个方向是否有新鲜橘子,有则将其腐烂,并存入队列
  • 由于队列中的橘子腐烂向外蔓延是同时发生的,我们每次将此时队列腐烂橘子数量记下,用一个for循环一次性处理完

BFS的代码框架(伪代码):

while (!queue.empty()){
    
    
	cur_node = queue.front();
	for(node : cur_node的相邻结点){
    
    
		if(node没被访问过){
    
    
			queue.push(node);
		}
	}
}

如果用上面这种写法来遍历,我们是无法区分 BFS 遍历中的每一“层”的。这是因为,遍历的时候,第 1 层的结点还没出完队列,第 2 层的结点就进来了。这个队列中第 1 层和第 2 层的结点会紧挨在一起,无法区分,也就无法知道当前正在腐烂的橘子所经历的时间time。

因此,我们需要修改一下代码,在每一层遍历开始前,记录队列中的结点数量 n ,然后一口气处理完这一层的 n 个结点 。然后遍历下一层的时候,把变量 time 加一

class Solution {
    
    
public:
    int orangesRotting(vector<vector<int>>& grid) {
    
    
        int fresh = 0;
        queue<pair<int,int>> roted;
        for(int i=0; i<grid.size(); i++){
    
    
            for(int j=0; j<grid[0].size(); j++){
    
    
                if(grid[i][j] == 1){
    
    
                    fresh++;//记录新鲜橘子数量
                }else if(grid[i][j] == 2){
    
    
                    roted.push(pair<int,int>(i,j));//存放腐烂橘子的坐标
                }
            }
        }

        int x_d[4] = {
    
    1,-1,0,0};
        int y_d[4] = {
    
    0,0,1,-1};
        int time = 0;
        while(!roted.empty()){
    
    
            int n = roted.size();//为方便记下访问的轮数,记下此时队列中的橘子数,一次访问完
            bool isRoted = false;
            for(int i=0; i<n; i++){
    
    //一轮循环访问队列中一个橘子的相邻结点
                int cur_x = roted.front().first;
                int cur_y = roted.front().second;
                roted.pop();
                for(int d=0; d<4; d++){
    
    
                    if(cur_x+x_d[d] >= grid.size() || cur_x+x_d[d] < 0 || cur_y+y_d[d] >= grid[0].size() || cur_y+y_d[d] < 0){
    
    
                     continue;
                     }
                    if(grid[cur_x+x_d[d]][cur_y+y_d[d]] == 1){
    
    //遇到新鲜橘子
                        grid[cur_x+x_d[d]][cur_y+y_d[d]] = 2;
                        roted.push(pair<int,int>(cur_x+x_d[d],cur_y+y_d[d]));
                        fresh--;//新鲜橘子减1
                        isRoted = true;
                    }
                }
            }
            if(isRoted) time++;//本轮有新鲜橘子腐烂
            else break;//本轮没有新鲜橘子腐烂,表示不会再有橘子腐烂了,此时队列也为空,直接跳出
        }
        return fresh == 0 ? time : -1;
    }
};

在这里插入图片描述

三、地图分析(bfs)

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
个人认为解这题最关键的就是理解“曼哈顿距离”以及题目中描述的“离它最近的陆地距离是最大的”这两个描述

  • 由曼哈顿距离的公式可知,此距离就是一个人在格子中只能往上下左右四个方向走(广搜每次只能搜索相邻的格子,这就和橘子腐烂的问题一样了),从一个格子走到另一个格子所走的次数
  • 我们从陆地出发,搜索海洋。每次将搜索到的海洋置为陆地,入队列,距离加 1。下次从新入队列的陆地开始向相邻的结点搜索,没有新的陆地进入队列,无法向前搜索,此时得到的距离就是所需要求得“最大距离”

BFS 可以看成是层序遍历。从某个结点出发,BFS 首先遍历到距离为 1 的结点,然后是距离为 2、3、4…… 的结点。因此,BFS 可以用来求最短路径问题。BFS 先搜索到的结点,一定是距离最近的结点。反之,BFS 最后搜索到的结点,就是距离最远的结点
在这里插入图片描述

举例

海洋和陆地的初始状态如下:
在这里插入图片描述
搜索过程如下:
在这里插入图片描述
其实这题思路转换一下,和橘子腐烂问题一模一样,连代码都一样

int maxDistance(vector<vector<int>>& grid) {
    
    
        queue <pair<int, int>> lands;
        for(int i=0; i<grid.size(); i++){
    
    
            for(int j=0; j<grid[0].size(); j++){
    
    
                if(grid[i][j] == 1){
    
    
                    lands.push(pair<int,int>(i,j));//所有陆地入队列,作为第一层结点9
                }
            }
        }
        if(lands.size() == grid.size()*grid[0].size() || lands.size() == 0){
    
    
            return -1;
        }
        int x_d[4] = {
    
    1,-1,0,0};
        int y_d[4] = {
    
    0,0,1,-1};
        int dis = 0;
        
        while(!lands.empty()){
    
    
            bool new_land = false;
            int n = lands.size();
            for(int i=0; i<n; i++){
    
    
                int cur_x = lands.front().first;
                int cur_y = lands.front().second;
                lands.pop();
                for(int d=0; d<4; d++){
    
    
                    int x = cur_x+x_d[d];//此时访问的格子坐标
                    int y = cur_y+y_d[d];
                    if(x<0 || x>=grid.size() || y<0 || y>=grid[0].size() ){
    
    //越界
                        continue;//此方向越界,继续下一次循环
                    }
                    if(grid[x][y] == 0){
    
    //遇到海洋
                        grid[x][y] = 1;
                        lands.push(pair<int,int>(x,y));
                        new_land = true;//表示有新的陆地入队,需要再搜索一轮
                    }
                }
            }
            if(new_land) dis++;
            else break;
        }
        return dis;
    }

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_42500831/article/details/105474126