BFS的上下左右搜索问题(递归和迭代)

news/2024/9/29 9:04:36 标签: 开发语言, c++, 算法, 递归, 回归, 数组

目录

一·题目(单词搜索问题):

二·思路解释:

三·解答代码:

​编辑   

四·题目(腐烂的苹果):

五·思路解释:

六·解答代码:   

             ​​​​


 

一·题目(单词搜索问题):

newcode题目链接: 单词搜索_牛客题霸_牛客网

二·思路解释:

思路:个人理解是找到word中的第一个元素,然后去递归的上下左右查找,最后根据word的下标变化等看是否返回true

下面具体说一下个人思路(也是根据大佬悟出来的):这里有点明显想考的是递归的使用,这里为了方便记录遍历到原数组位置

以及防止查找时候查到已经找到的原数组中元素(word中有连续重复元素在board中出现)等,因此不方便在原数组里面操作,因此重新建一个二维数组(这里个人称作真假表->主要记录遍历原数组找到元素位置,给它在真假表中用true标记,而默认是false,这里标记它的路径也能防止“走重的操作了”).

因此这里首先建立一个递归函数,首先要想完成这个操作需要哪些参数等呢? word和它的索引 ,board和它的下标i,j,以及我们的真假表(这里下标直接用board的i,j即可);

一开始先遍历原数组找到word首元素的位置,从它开始进行递归(当然这里有种特殊情况,下面会讲到)

1·首先不是递归嘛:然后先找递归终止条件这里可以根据遍历上下左右的时候出现的越界问题,总结了四个返回false的情况,根据后面的查找操作也不难找出另两个即可能出现查找了曾经找的元素+不是word中对应下标所指向的元素。-->这里就得到了递归不成立的六大终止条件。   如果我们根据实例1试到最后一次对归还会发现最后一次如果再次遍历,它应该设置一个返回真的条件 ,于是就得到了另一个返回真的条件--->也就是当word索引越界的情况

2·也就是如何递归,这里如果上面没有被返回也就是到了下面也就是找到了,因此可以在真假表对应映射位置填入true,然后接着往它左右递归即可,最后呢根据递归完往回溯可以看出这里最后返回的上下左右的bool类型值应该是或的关系。

3·这里可以考虑给真假表对应的当时填入true位置复原成false(当然这里对本题解无关系)

这里有一个细节问题;也就是上面说的,这里找到对应word[0],我们就返回这个递归函数,这里是错误的(表示掉过坑),这里可能是这种情况:["CAA","AAA","BCD"] "AAB"-->这里如果找到第一个A,然后递归下去最后返回的一定是false,然而此例子返回的应该是true,因此如果它是false就接着遍历board继续找,然后再次递归, 因此这里如果递归函数返回false不一定题解真实false,但是如果返回true则题解一定是true。,因此注意好这个基本到这就没什么问题了。

下面画图以实例1为例子解释如何递归的:

 

三·解答代码:

                  

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param board string字符串vector 
     * @param word string字符串 
     * @return bool布尔型

     */
     bool recursion_find(vector<string>& board,int i,int j, string word,int word_index,vector<vector<bool>>TF_graph){
        if(word_index==word.size()) return true;
         if(i<0||i>=board.size()||j<0||j>=board[0].size()||TF_graph[i][j]==true||board[i][j]!=word[word_index]) return false;
         
         TF_graph[i][j]=true;
         bool target_on=recursion_find(board,i-1,j,word,word_index+1,TF_graph);
         bool target_under=recursion_find(board,i+1,j,word,word_index+1,TF_graph);
         bool target_left=recursion_find(board,i,j-1,word,word_index+1,TF_graph);
         bool target_right=recursion_find(board,i,j+1,word,word_index+1,TF_graph);
         // TF_graph[i][j]=false;
         return  target_on||target_under||target_left|| target_right;
            

     }
    bool exist(vector<string>& board, string word) {
         int m=board.size();
         int n=board[0].size();
         vector<vector<bool>>TF_graph(m,vector<bool>(n,false));
         for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(board[i][j]==word[0]){
                    //return recursion_find(board,i,j,word,0,TF_graph);
                   if (recursion_find(board,i,j,word,0,TF_graph)) {
                        return true;
                    }
                }
                
            }
         }
         return false;

    }
};

   

四·题目(腐烂的苹果):

nowcoder题目链接:腐烂的苹果_牛客题霸_牛客网 

五·思路解释:

思路:这里虽然是bfs有两种思路的方向可以让我们完成代码的操作,一个就是递归,另一个就是迭代,这里考虑一下迭代完成,

即通过选择合容器配合出入以及循环完成。下面讲解一下迭代应用于本题的具体思路:

1·首先这道题就是我们先遍历数组然后找到所有的2,之后在同时从每个2开始上下左右找1覆盖成2并记录位置,并把它们就录下来方便下次用,第一批2用完后,这时是过去了一分钟故用个计时器记录一下,然后拿到刚刚保存的那些2重复操作即可,最后呢要么里面还有1没有被修改要么就是2和0了,这里如果有1那么就返回-1,否则返回这个计时器记录的就可。

2·思路的进一步转化:由上面的思路,如保存一些2的位置然后后面还要添加方便再一次使用,很容易想到队列,这里还有两个要处理

如何控制它每次都是用完保存的第一批然后再用第二批,那么此时可以用一个size记录第一批长度然后再入第二批,依次对size减减,另一个就是什么时候开始计时? 根据题意我们可以知道每次的同一批2是同时查找的故这就是一分钟,因此一批过后才计数器加加

 

当然这里还有一个更细节问题需要处理就是我们的计时器:先说结论这里计时器count,如果找不到1,那么应该返回的是cout-1;为什么呢?这里不是,每次队列里每减完一批2所在位置那么count就加加,我们可以根据例1推算出,结论:当走到最后的那批,此时这批是无法找到再下一批的但是还会使得count++,故这次应该不算,但是我们把它算进去了,故应该减去。

 

下面画图解释一下: 

 

六·解答代码:   

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param grid int整型vector<vector<>> 
     * @return int整型
     */
     queue<pair<int,int>>q;
     int count=0;
//这里写一个函数判断下标是否越界问题:
       bool judge(vector<vector<int> >& grid,int m,int n){
       if (m<0||m>=grid.size()||n<0||n>=grid[0].size()) return false;
       else return true;
        
     }
      //子函数利用容器特点把递归转换成迭代解决:
         void bfs(vector<vector<int> >& grid,int &count){
            
           while(!q.empty()){
            int size=q.size();
            while(size--){
                pair<int,int> f=q.front();
                q.pop();
                int i=f.first;
                int j=f.second;
                if(judge(grid,i,j-1)&&grid[i][j-1]==1){
                     q.push(make_pair(i,j-1));
                     grid[i][j-1]=2;
                }
                if(judge(grid,i,j+1)&&grid[i][j+1]==1){
                     q.push(make_pair(i,j+1));
                     grid[i][j+1]=2;
                }
                if(judge(grid,i-1,j)&&grid[i-1][j]==1){
                     q.push(make_pair(i-1,j));
                     grid[i-1][j]=2;
                }
                if(judge(grid,i+1,j)&&grid[i+1][j]==1){
                     q.push(make_pair(i+1,j));
                     grid[i+1][j]=2;
                }



            }
                     count++;
           }
     }

    int rotApple(vector<vector<int> >& grid) {
        // write code here
             for(int i=0;i<grid.size();i++){
                for(int j=0;j<grid[0].size();j++){
                    if(grid[i][j]==2){
                        q.push(make_pair(i,j));
                    }
                    
                }
             }
             bfs(grid,count);
             for(int i=0;i<grid.size();i++){
                for(int j=0;j<grid[0].size();j++){
                    if(grid[i][j]==1) return -1;
                        
                    
                    
                }
             }
             return count-1;
             
    }
};

             ​​​​

 若有补充希望大佬们留言.        


http://www.niftyadmin.cn/n/5682725.html

相关文章

[SAP ABAP] SELECTION-SCREEN

SELECTION-SCREEN用来调节系统生成的画面 REPORT z437_test_2024.TABLES: mara, zdbt_sch_437.SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001. " Title1 PARAMETERS:p_1 DEFAULT A,p_2 TYPE char10. SELECTION-SCREEN END OF BLOCK b1.SELECTION-SCREEN …

Spring、SpringBoot 框架功能学习

一. Spring核心功能 依赖注入&#xff08;DI&#xff09;&#xff1a;Spring的核心功能是通过依赖注入来管理对象之间的依赖关系。依赖注入是一种将对象的依赖关系注入到被依赖对象中的机制&#xff0c;它可以帮助降低对象之间的耦合度&#xff0c;使得代码更容易维护和测试。 …

W39-02-jmeter中如何实现:下一个请求是需要根据前一个请求返回值进行循环请求

业务压测需求&#xff1a; 查询和上报接口&#xff0c; 1.查询接口返回的数据有好几条需要上报的数据 2.查询接口中返回的每条数据中&#xff0c;有两个字段需要传递到上报接口 3.查询接口中&#xff0c;这两个字段一个为int型&#xff0c;一个为数组[1,2,3,4] 实现方式 …

MFC单按钮启停实例

单击按钮启动、停止交替切欣换 1、在1Dlg.h文件中添加代码 public:CMy1Dlg(CWnd* pParent NULL); // standard constructorBOOL m_b;2、在1Dlg.cpp文件中添加代码 CMy1Dlg::CMy1Dlg(CWnd* pParent /*NULL*/): CDialog(CMy1Dlg::IDD, pParent) { m_hIcon AfxGetApp()->Lo…

opencv:实现图像的自动裁剪与优化

随着计算机视觉技术的发展&#xff0c;图像处理已成为一项重要的技能。今天&#xff0c;我们将探讨如何使用Python中的OpenCV库来实现对图像的自动裁剪以及一些基本的图像优化技巧。我们的目标是对一张发票图片进行处理&#xff0c;使其更加清晰且便于阅读。 准备工作 首先&a…

【Python】Django Grappelli:打造优雅且现代化的 Django 管理后台

在 Django 开发中&#xff0c;默认的 Django Admin 界面尽管功能强大且能满足大多数管理需求&#xff0c;但其界面设计相对基础&#xff0c;尤其在用户体验和视觉呈现上显得较为简约。在一些项目中&#xff0c;开发者可能需要更加现代化且美观的后台界面。这时&#xff0c;Djan…

C++第3课——保留小数点、比较运算符、逻辑运算符、布尔类型以及if-else分支语句(含视频讲解)

文章目录 1、课程笔记2、课程视频 1、课程笔记 #include<iostream>//头文件 input output #include<cmath> //sqrt()所需的头文件 #include<iomanip>//setprecision(1)保留小数点位数所需的头文件 using namespace std; int main(){/*复习上节课内容1、…

【TypeScript】面向对象

文章目录 面向对象TypeScript 接口详解接口的基本定义示例 联合类型和接口示例 接口和数组示例 接口继承单接口继承多接口继承 TypeScript 类详解类的基本定义创建类创建实例化对象类的继承示例 方法重写示例 static 关键字示例 instanceof 运算符示例 访问控制修饰符示例 类与…