【递归、搜索与回溯】综合练习四

综合练习四

  • 1.单词搜索
  • 2.黄金矿工
  • 3.不同路径 III

在这里插入图片描述

点赞👍👍收藏🌟🌟关注💖💖
你的支持是对我最大的鼓励,我们一起努力吧!😃😃

1.单词搜索

题目链接:79. 单词搜索

题目分析:

在这里插入图片描述

给一个mxn board二维数组,让在数组中找是否存在字符串单词 word,注意只能上下左右去找,不能斜着找。

算法原理:
我们在这个矩阵中依次找到word里面的所有字符。首先在这个矩阵里面先一行一行的扫描找到word里面第一个字符,当找到第一个字符时,就从这个字符开始去匹配其他剩余的字符,注意只能上下左右去匹配,如果上下左右都不匹配说明这个位置是一次失败的匹配。那就在去找其他位置能匹配的第一个字符。如果找到还是上下左右去匹配,如果能匹配成功说明这个矩阵有这个单词。

在这里插入图片描述

如果把这道题抽象一下,你会发现刚刚的过程j就是解决迷宫常用的方式,深度优先遍历。如果走不通就回溯一下再往下走,直到找到一个正确结果为止。

在这里插入图片描述
接下来我们考虑递归函数如何设计,从某个节点开始上下左右匹配下一个字符,所以则函数体干的就是给一个位置然后上下左右去匹配下一个字符。这个参数首先把这个board给我,然后第一个字符的位置,然后给我要匹配字符串中下一个字符的位置。dfs(board,i,j,s,pos),注意看这个决策树我们从一个位置走可能走失败,上面调用dfs的得知道是找成功还是失败,所以dfs有一个bool类型的返回值,
bool dfs(board,i,j,s,pos) 失败就去另一条路径。剪枝就是那一个位置能匹配就去走那一个位置。回溯 一条路径找失败往上走就是回溯,往下走之前你弄了什么,反着来就可以了。

下面是细节问题:二维矩阵搜索中,经常要注意的细节。
不能走重复的路
就比如下面的这个位置,一直会是重复的。之前用过的下一次不能在找了。
在这里插入图片描述
这里我们有两种方法规避。

  1. 搞一个bool类型的跟原始数组大小一样的二维数组 bool visit[][]。用这个数组来标记当前这个位置是否被使用过。使用过就把这个位置标记成true。然后到下一层的时候就考虑一下上一个位置是否是ture,是就不走,不是就可以走。
  2. 修改原始矩阵的值。 比如说把被使用的位置的值修改成*,面试时还是要问一下能否修改,能修改再用这种方法。但是还有一个问题你修改完去往下一层,然后再回来的时候你要把被修改的值在还原回来。

这里在写代码去上下左右匹配的时候有两种写法:

  1. 可以分别写上下左右四个函数去匹配。
  2. 我们可以用向量的方式,定义上下左右四个位置。 然后仅需一次for循环就可以把上下左右都考虑进去了。

单独看这个i,上下左右就是在原始的i基础上要么不变,要么+1,要么-1,所以可以搞一个数组 int dx[4]={0,0,1,-1}; 这个表示i接下来可能的偏移量。同理j也有四个偏移量 int dy[4]={-1,1,0,0}; 然后这两个就可以上下凑一起使用。
在这里插入图片描述

class Solution {
    bool check[7][7];
    int m,n;
public:
    bool exist(vector<vector<char>>& board, string word) {
        m=board.size(),n=board[0].size();

        for(int i = 0; i < m; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                if(board[i][j] == word[0])
                {
                    check[i][j]=true;
                    if(dfs(board,i,j,word,1)) return true;
                    check[i][j]=false;
                }
            }
        }
        return false;
    }

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

    bool dfs(vector<vector<char>>& board,int i,int j,string& s,int pos)
    {
        if(pos == s.size()) return true;

        for(int k = 0; k < 4; ++k)
        {
            int x=i+dx[k],y=j+dy[k];

            if(x >= 0 && x < m && y >= 0 && y < n && check[x][y] == false && board[x][y] == s[pos])
            {
                check[x][y]=true;
                if(dfs(board,x,y,s,pos+1)) return true;
                check[x][y]=false;
            }
        }
        return false;

    }

};

2.黄金矿工

题目链接:1219. 黄金矿工

题目分析:

在这里插入图片描述

这道题和上面单词搜索就是同属于一类题,这里也是上下左右去搜索,不能走重复路。当天这里还有要求不能开采为0的单元格。

算法原理:
我们还是先去遍历找到不为0的单元格,然后从这个位置开始上下左右去递归,注意已经被选过的下次不能在选,可以弄一个原数组大小bool类型二维数组,当然也可以修改原始的值。其余的几乎和上面题一模一样。
在这里插入图片描述
修改原始的值

class Solution {
    int m,n,ret;
public:
    int getMaximumGold(vector<vector<int>>& grid) {
        m=grid.size(),n=grid[0].size();

        for(int i = 0; i < m; ++i)
        {
            for(int j = 0; j < n ; ++j)
            {
                if(grid[i][j] != 0)
                {
                    int num=grid[i][j];
                    grid[i][j]=0;
                    dfs(grid,i,j,num);
                    grid[i][j]=num;
                }
            }
        }
        return ret;
    }

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

    void dfs(vector<vector<int>>& grid,int i,int j,int path)
    {
    	//每次递归进来就统计,不用硬找递归出口
        ret=max(ret,path);

        for(int k = 0; k < 4; ++k)
        {
            int x=i+dx[k],y=j+dy[k];
            if(x >= 0 && x < m && y >= 0 && y < n && grid[x][y] != 0)
            {
                int num=grid[x][y];
                grid[x][y]=0;
                dfs(grid,x,y,path+num);
                grid[x][y]=num;
            }
        }
    }
};
class Solution
{
	 bool vis[16][16];
	 int dx[4] = {0, 0, 1, -1};
	 int dy[4] = {1, -1, 0, 0};
	 int m, n;
	 int ret;
public:
	 int getMaximumGold(vector<vector<int>>& grid) 
	 {
		 m = g.size(), n = g[0].size();
		 for(int i = 0; i < m; i++)
		 {
			 for(int j = 0; j < n; j++)
			 {
				 if(grid[i][j])
				 {
					 vis[i][j] = true;
					 dfs(grid, i, j, grid[i][j]);
					 vis[i][j] = false;
				 }
			 }
		}
		 return ret;
    }
    
	void dfs(vector<vector<int>>& grid, int i, int j, int path)
	{
		ret = max(ret, path);
		for(int k = 0; k < 4; k++)
		{
			int x = i + dx[k], y = j + dy[k];
			if(x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && grid[x][y])
			{
				vis[x][y] = true;
				dfs(grid, x, y, path + grid[x][y]);
				vis[x][y] = false;
			}
		}
	}
};

3.不同路径 III

题目链接:980. 不同路径 III

题目分析:

在这里插入图片描述

这个棋盘,1代表开始,2代表结束,0表示可以走过的方格,-1表示障碍。
从开始到结束有很多的走法,但是仅有两种路径把所有0方格都通过一次。

在这里插入图片描述
算法原理:
我们策略就是把从1走到2所有合法的路径个数统计出来。我们可以先扫描出数组找到起始位置,然后从这个起始位置开始dfs,不管你怎么走的,只要走到2你这条路径是合法的就行了。如何判断合法特别简单,向下递归的时候用一个count变量记录一下从开始到结束所走的这条路径个数。当走到2的时候判断一下这个count和我实际要走的步数step是否一样,实际要走步数在dfs之前把先描述整个数组先统计这个数组0有多少个,然后在加上起始位置和结束位置就是实际要走的步数。如果走到2 count == step 就找到一条路径。不相等就不统计。然后继续暴搜直到把所有能到2的路径合法的统计出来。

class Solution {
    bool vis[21][21];
	 int dx[4] = {0, 0, 1, -1};
	 int dy[4] = {1, -1, 0, 0};
    int m,n;
    int ret,step;
public:
    int uniquePathsIII(vector<vector<int>>& grid) {
        m=grid.size(),n=grid[0].size();
        int beginx,beginy;

        // 统计0的个数 以及 开始的地方
        for(int i = 0; i < m; ++i)
        {
            for(int j = 0; j < n ; ++j)
            {
                if(grid[i][j] == 0) ++step;
                else if(grid[i][j] == 1) 
                {
                    beginx=i;
                    beginy=j;
                }

            }
        }
        // 到底终点所需步数
        step += 2;
        vis[beginx][beginy]=true;
        dfs(grid,beginx,beginy,1);
        return ret;
    }

    void dfs(vector<vector<int>>& grid,int i,int j,int count)
    {
        if(grid[i][j] == 2) 
        {
            if(count == step) //判断是否合法
                ++ret;
            return;
        }

        for(int k = 0; k < 4; ++k)
        {
            int x = i + dx[k], y = j + dy[k];
            if(x >= 0 && x < m && y >= 0 && y < n && !vis[x][y] && grid[x][y] != -1)
            {
                vis[x][y]=true;
                dfs(grid,x,y,count+1);
                vis[x][y]=false;
            }
        }
    }
};

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

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

相关文章

前端路线指导(3):前端进阶版学习路线

前端进阶版学习路线&#xff1a; 哈喽大家好&#xff01;我是小粉&#xff0c;双一流本科&#xff0c;自学前端一年&#xff0c;收获腾讯&#xff0c;字节等9家互联网大厂offer&#xff0c;秋招面试通过率100%&#xff0c;其中半数offer为ssp&#xff08;薪资最高档&#xff09…

如何查看公网IP?

什么是公网IP&#xff1f; 公网IP&#xff08;Internet Protocol&#xff09;是指分配给互联网上的计算机设备的唯一标识符。公网IP地址是由互联网服务提供商&#xff08;ISP&#xff09;分配给用户设备&#xff0c;使其可以与全球范围内的其他设备进行通信。公网IP地址通常采…

【超越拟合:深度学习中的过拟合与欠拟合应对策略】

如何处理过拟合 由于过拟合的主要问题是你的模型与训练数据拟合得太好&#xff0c;因此你需要使用技术来“控制它”。防止过拟合的常用技术称为正则化。我喜欢将其视为“使我们的模型更加规则”&#xff0c;例如能够拟合更多类型的数据。 让我们讨论一些防止过拟合的方法。 获…

代理模式(静态代理/动态代理)

代理模式&#xff08;Proxy Pattern&#xff09; 一 定义 为其他对象提供一种代理&#xff0c;以控制对这个对象的访问。 代理对象在客户端和目标对象之间起到了中介作用&#xff0c;起到保护或增强目标对象的作用。 属于结构型设计模式。 代理模式分为静态代理和动态代理。…

视频监控统一管理平台LntonCVS安防视频监控系统视频汇聚方案

LntonCVS平台最初被设计为一个以视频汇聚为核心的平台。那么&#xff0c;什么是视频汇聚平台&#xff0c;以及它是如何处理视频资源的呢&#xff1f;简单来说&#xff0c;视频汇聚平台能够从不同的视频源&#xff08;如直播和点播&#xff09;收集、整合和展示视频内容。以下是…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 身高差值排序(100分) - 三语言AC题解(Python/Java/Cpp)

&#x1f36d; 大家好这里是清隆学长 &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f497; &#x1f…

vue3+element ui +ts 封装周范围选择器

vue3element ui ts 封装周范围选择器 在业务场景中&#xff0c;产品需要在页面中使用周范围选择器&#xff0c;我们在使用ant-design的时候里面是有自带的&#xff0c;但是在emement中只有指定周的范围选择器&#xff1a; 这个是ant-design的周范围选择器 这个是element ui 的…

.net 奇葩问题调试经历之1——在红外相机获取温度时异常

📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!📢本文作者:由webmote 原创📢作者格言:新的征程,我们面对的不仅仅是技术还有人心,人心不可测,海水不可量,唯有技术,才是深沉黑夜中的一座闪烁的灯塔序言 我们在研发中,经常除了造产品…

C#的Switch语句2(case后的值与模式匹配)

文章目录 switch语法结构case具体的值枚举值字符串const关键字 如果没有匹配的值default语句不一定要在最后 模式匹配与C的差异-case穿透&#xff08;Fall-through&#xff09;下一篇文章 switch语法结构 基础的语法结构&#xff0c;在上一篇文章已经写了&#xff0c;具体请看…

Shiro550 反序列化漏洞(CVE-2016-4437)

目录 Shiro介绍 漏洞原理 判断是否存在漏洞 利用ShiroExploit工具执行命令&#xff1a; 利用shiro-exploit工具综合利用工具执行命令&#xff1a; 这一篇是参考别的师傅的好文章对Shiro550反序列化漏洞的学习和练习 Shiro介绍 Apache Shiro是一个强大易用的java安全框架…

ASP.NET MVC企业级程序设计(增删,页面水平排列,字符串拼接,非空,添加框内默认提示)

目录 题目&#xff1a; 实现过程 控制器代码 DAL BLL Index Deile 题目&#xff1a; 实现过程 控制器代码 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using MvcApplication1.Models;namespac…

Tensorflow入门实战 T05-运动鞋识别

目录 一、完整代码 二、训练过程 &#xff08;1&#xff09;打印2行10列的数据。 &#xff08;2&#xff09;查看数据集中的一张图片 &#xff08;3&#xff09;训练过程&#xff08;训练50个epoch&#xff09; &#xff08;4&#xff09;训练结果的精确度 三、遇到的问…

Docker环境离线安装

Docker环境离线安装 下载下列.deb包 sudo *.deb

【PyQt5】python桌面级应用开发:PyQt5介绍,开发环境搭建快速入门

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

天津媒体邀约,及媒体名单?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体宣传加速季&#xff0c;100万补贴享不停&#xff0c;一手媒体资源&#xff0c;全国100城线下落地执行。详情请联系胡老师。 天津作为中国北方的重要城市&#xff0c;拥有丰富的媒体资…

Jenkins+K8s实现持续集成(二)

部署前呢&#xff0c;要先把jenkins搭建好。 同时呢已经有了k8s的环境。 基于以上两步已经有了的情况&#xff0c;继续要实现jenkinsk8s持续集成&#xff0c;需要先准备四个文件&#xff1a; Dockerfile首先要准备好一个Dockerfile文件&#xff0c;用于构建Docker镜像的文本…

最新版本IntelliJ IDEA安装与“坤活”使用

最新版本IntelliJ IDEA安装与“科学”使用 IntelliJ IDEA安装与坤活下载安装坤活idea1.将下面两个压缩文件解压到安装位置&#xff0c;注意路径不要包含中文空格等特殊符号2.双击 install-all-users.vbs &#xff0c;然后点击确定&#xff0c;等到出现 Done的弹窗3. 打开idea复…

函数依赖集等价、最小函数依赖集

一、函数依赖集等价 1、定义 假设F、G为一个关系模式上的两个函数依赖集&#xff0c;若&#xff0c;则称F和G是等价的&#xff0c;也可称F和G 互相覆盖。 2、判断 &#xff08;1&#xff09;引理3&#xff1a; 的充分必要条件是且 &#xff08;2&#xff09;两步走&…

密码学及其应用——为什么选择接近的质数因子对RSA加密算法不安全?

RSA加密算法是一种广泛使用的非对称加密算法&#xff0c;它的安全性依赖于大整数分解的难度。具体来说&#xff0c;RSA算法生成的公钥包含一个大整数N&#xff0c;这是两个大质数p和q的乘积。然而&#xff0c;如果这两个质数p和q太接近&#xff0c;则可以相对容易地对N进行因式…

Study--Oracle-04-SQL练习

一、SQL语句思维导图 二、SQL练习 -- 以employee_id 为排序&#xff0c;列出前5个人 -- FETCH select employee_id,first_name from employees order by employee_id FETCH FIRST 5 rows only; -- 以employee_id 为排序&#xff0c;从第6个人开始 到第10个人 -- offset …