递归 与 dfs 综合练习(四)

news2024/9/21 22:41:41

目录

一、单词搜索

1.题目链接:79. 单词搜索

2.题目描述:

3.解法

🌴算法思路:

🌴算法代码:

一、黄金矿工

1.题目链接:1219. 黄金矿工

2.题目描述:

3.解法

🌴算法思路:

🌴算法代码:

一、不同路径 III

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

2.题目描述:

3.解法

🌴算法思路:

🌴算法代码:


一、单词搜索

1.题目链接:79. 单词搜索

2.题目描述:

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

示例 1:

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出:true

示例 2:

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE"
输出:true

示例 3: 

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCB"
输出:false

提示:

  • m == board.length
  • n = board[i].length
  • 1 <= m, n <= 6
  • 1 <= word.length <= 15
  • board 和 word 仅由大小写英文字母组成

3.解法

🌴算法思路:

        我们需要假设每个位置的元素作为第⼀个字母,然后向相邻的四个方向进行递归,并且不能出现重复使用同⼀个位置的元素。通过深度优先搜索的方式,不断地枚举相邻元素作为下⼀个字母出现的可能性,并在递归结束时回溯,直到枚举完所有可能性,得到正确的结果。


递归函数设计:bool dfs(int x, int y, int step, vector<vector<char>>& board, string word, vector<vector<bool>>& vis, int &n, int &m, int &len)

  • 参数:x(当前需要进行处理的元素横坐标),y(当前需要进行处理的元素横坐标),step(当前已经处理的元素个数),word(当前的字符串状态);
  • 返回值:当前坐标元素作为字符串中下标 step 的元素出现是否可以找到成立的字符串。
  • 函数作用:判断当前坐标的元素作为字符串中下标 step 的元素出现时,向四个方向传递,查找是否存在路径结果与字符串相同。

递归函数流程:

1. 遍历每个位置,标记当前位置并将当前位置的字母作为首字母进行递归,并且在回溯时撤回标记。

2. 在每个递归的状态中,我们维护⼀个步数 step,表示当前已经处理了几个字母。

  • 若当前位置的字母与字符串中的第 step 个字母不相等,则返回 false。
  • 若当前 step 的值与字符串长度相等,表示存在⼀种路径使得 word 成立,返回 true。

3. 对当前位置的上下左右四个相邻位置进行递归,若递归结果为 true,则返回 true。

4. 若相邻的四个位置的递归结果都为 false,则返回 false。

  • 特别地,如果使用将当前遍历到的字符赋值为空格,并在回溯时恢复为原来的字母的方法,则在递归时不会重复遍历当前元素,可达到不使用标记数组的目的。

🌴算法代码:

class Solution 
{
    bool vis[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])
                {
                    vis[i][j] = true;
                    if (dfs(board, i, j, word, 1)) return true;
                    vis[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 word, int pos)
    {
        if (pos == word.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 && !vis[x][y] && board[x][y] == word[pos])
            {
                vis[x][y] = true;
                if (dfs(board, x, y, word, pos + 1)) return true;
                vis[x][y] = false;
            }
        }
        return false;
    }
};

一、黄金矿工

1.题目链接:1219. 黄金矿工

2.题目描述:

你要开发一座金矿,地质勘测学家已经探明了这座金矿中的资源分布,并用大小为 m * n 的网格 grid 进行了标注。每个单元格中的整数就表示这一单元格中的黄金数量;如果该单元格是空的,那么就是 0

为了使收益最大化,矿工需要按以下规则来开采黄金:

  • 每当矿工进入一个单元,就会收集该单元格中的所有黄金。
  • 矿工每次可以从当前位置向上下左右四个方向走。
  • 每个单元格只能被开采(进入)一次。
  • 不得开采(进入)黄金数目为 0 的单元格。
  • 矿工可以从网格中 任意一个 有黄金的单元格出发或者是停止。

示例 1:

输入:grid = [[0,6,0],[5,8,7],[0,9,0]]
输出:24
解释:
[[0,6,0],
 [5,8,7],
 [0,9,0]]
一种收集最多黄金的路线是:9 -> 8 -> 7。

示例 2:

输入:grid = [[1,0,7],[2,0,6],[3,4,5],[0,3,0],[9,0,20]]
输出:28
解释:
[[1,0,7],
 [2,0,6],
 [3,4,5],
 [0,3,0],
 [9,0,20]]
一种收集最多黄金的路线是:1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7。

提示:

  • 1 <= grid.length, grid[i].length <= 15
  • 0 <= grid[i][j] <= 100
  • 最多 25 个单元格中有黄金。

3.解法

🌴算法思路:

        枚举矩阵中所有的位置当成起点,来⼀次深度优先遍历,统计出所有情况下能收集到的黄金数的最大值即可。

🌴算法代码:

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 = grid.size(), n = grid[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;
            }
        }
    }
};

一、不同路径 III

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

2.题目描述:

在二维网格 grid 上,有 4 种类型的方格:

  • 1 表示起始方格。且只有一个起始方格。
  • 2 表示结束方格,且只有一个结束方格。
  • 0 表示我们可以走过的空方格。
  • -1 表示我们无法跨越的障碍。

返回在四个方向(上、下、左、右)上行走时,从起始方格到结束方格的不同路径的数目

每一个无障碍方格都要通过一次,但是一条路径中不能重复通过同一个方格

示例 1:

输入:[[1,0,0,0],[0,0,0,0],[0,0,2,-1]]
输出:2
解释:我们有以下两条路径:
1. (0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(2,2)
2. (0,0),(1,0),(2,0),(2,1),(1,1),(0,1),(0,2),(0,3),(1,3),(1,2),(2,2)

示例 2:

输入:[[1,0,0,0],[0,0,0,0],[0,0,0,2]]
输出:4
解释:我们有以下四条路径: 
1. (0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(2,2),(2,3)
2. (0,0),(0,1),(1,1),(1,0),(2,0),(2,1),(2,2),(1,2),(0,2),(0,3),(1,3),(2,3)
3. (0,0),(1,0),(2,0),(2,1),(2,2),(1,2),(1,1),(0,1),(0,2),(0,3),(1,3),(2,3)
4. (0,0),(1,0),(2,0),(2,1),(1,1),(0,1),(0,2),(0,3),(1,3),(1,2),(2,2),(2,3)

示例 3:

输入:[[0,1],[2,0]]
输出:0
解释:
没有一条路能完全穿过每一个空的方格一次。
请注意,起始和结束方格可以位于网格中的任意位置。

提示:

  • 1 <= grid.length * grid[0].length <= 20

3.解法

🌴算法思路:

        对于四个方向,我们可以定义⼀个二维数组 next ,大小为 4 ,每⼀维存储四个方向的坐标偏移量(详见代码)。题目要求到达目标位置时所有无障碍方格都存在路径中,我们可以定义⼀个变量记录 num 当前状态中剩余的未走过的无障碍方格个数,则当我们走到目标地点时只需要判断 num 是否为 0 即可。在移动时需要判断是否越界。


递归函数设计:void dfs(vector<vector<int>>& grid, int x, int y, int num)

参数:x,y(当前需要处理元素的坐标),num(当前剩余无障碍方格个数);

返回值:无;

函数作用:判断当前位置的四个方向是否可以添加至当前状态,查找在满足条件下从起始方格到结束方格的不同路径的数目。


递归流程如下:

1. 递归结束条件:当前位置的元素值为 2,若此时可走的位置数量 num 的值为 0,则 cnt 的值加一;

2. 遍历四个方向,若移动后未越界,无障碍并且未被标记,则标记当前位置,并递归移动后的位置,在回溯时撤销标记操作。

🌴算法代码:

class Solution 
{
    bool vis[21][21];
    int dx[4] = {1, -1, 0, 0};
    int dy[4] = {0, 0, 1, -1};
    int ret;
    int m, n, step;

public:
    int uniquePathsIII(vector<vector<int>>& grid) 
    {
        m = grid.size(), n = grid[0].size();
        int bx = 0, by = 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) 
                {
                    bx = i;
                    by = j;
                }
        step += 2;
        vis[bx][by] = true;
        dfs(grid, bx, by, 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;
            }
        }
    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《从C/C++到Java入门指南》- 25.final 关键字

final 关键字 final 变量 final变量可以理解为C中的const&#xff0c;变量一经定义无法修改。 public class Main {public static void main(String args[]) {final double PI 3.1415926;System.out.println(PI);// PI 3.14; // 尝试修改会报错} }final 方法 一个定义为f…

私有仓库

创建私有仓库,在企业中分享项⽬ # 创建仓库 # 重启docker服务 # 为要上传的镜像添加标记 1.拉取registry 2.创建挂载⽬录 3.启动容器&#xff0c;映射端⼝&#xff0c;挂载⽬录 4.访问仓库 5.配置pull和push&#xff0c;修改daemon.json 6.修改了配置⽂件&#xff0c;重启docke…

WordPress资源产品展示类主题 官网主题 CeoNova-Pro_v4.4

WordPress资源产品展示类主题 官网主题 CeoNova-Pro_v4.4 开心版 CeoNova-Pro主题是一款轻量级、且简洁大气、产品官网类主题&#xff0c;定位于高端产品官网、同时包含了知识付费、定制服务、问答社区、论坛交流、网址导航、以及付费产品购买下载等全方位覆盖。 CeoNova主题…

C#和数据类型转换

C#是一种强类型语言&#xff0c;这意味着每个变量的类型在编译时都是已知的。数据类型转换是指将一种数据类型的值转换为另一种数据类型的过程。在C#中&#xff0c;数据类型转换分为隐式转换和显式转换。本文将详细探讨这两种转换方式&#xff0c;并提供字符转16进制的解决方案…

除尘雾炮机的寿命一般是多久呢,需要维护吗

除尘雾炮机的寿命一般是5-10年左右&#xff0c;但具体寿命会受到设备质量、使用环境、使用频率及维护保养情况等多种因素的影响。朗观视觉小编接下来带您扒一扒&#xff01; 除尘雾炮机的寿命影响因素 设备质量&#xff1a;高质量的雾炮机采用优质材料和先进工艺制造&#xff…

自动化数据汇总:使用Python从多个数据源汇总数据

目录 引言 一、理论基础 1.1 数据源介绍 1.2 数据处理流程 1.3 常用库介绍 二、实践操作 2.1 数据读取 2.1.1 从CSV文件读取数据 2.1.2 从Excel文件读取数据 2.1.3 从数据库读取数据 2.2 数据处理 2.2.1 数据合并 2.3 数据汇总 2.4 数据存储 2.4.1 存储到CSV文件…

深度解析MFT损坏:原因、恢复策略与预防措施

一、MFT损坏现象揭秘 在Windows操作系统中&#xff0c;主文件表&#xff08;Master File Table&#xff0c;简称MFT&#xff09;是NTFS文件系统的核心组成部分&#xff0c;它记录了文件系统中所有文件的元数据&#xff0c;包括文件名、大小、创建和修改时间、数据位置等关键信…

【Spring】获取cookie,session,header(3)

本系列共涉及4个框架&#xff1a;Sping,SpringBoot,Spring MVC,Mybatis。 博客涉及框架的重要知识点&#xff0c;根据序号学习即可。 目录 本系列共涉及4个框架&#xff1a;Sping,SpringBoot,Spring MVC,Mybatis。 博客涉及框架的重要知识点&#xff0c;根据序号学习即可。…

ARM————体系结构

1、ARM结构框架 RAM&#xff1a;随机存储&#xff0c;存储速度快&#xff0c;掉电数据丢失SRAM 静态存储DRAM 动态存储SDRAM 同步存储DDR 双倍速率同步存储ROM&#xff1a;只读存储&#xff0c;存储速度慢&#xff0c;掉电不丢失数据PROM 可编程存储EPROM 可擦…

eureka一

Eureka 什么是eureka eureka服务调用流程 springcloud技术栈应用 分布式理论 CAP CAP理想运行情况 CAP不理想运行情况 CAP取舍 BASE BASE原理 搭建单机注册中心 服务提供者 服务消费者 集群服务注册中心 eureka功能详解 核心功能演示 Eureka源码解析 lifecycle的start

0基础轻松玩转.NET Web API 8.0【CICD】项目实战

1.背景 最近在学习CI/CD&#xff0c;为了加快熟悉CI/CD&#xff0c;我实操了下基于.Net 8.0的CI/CD项目实战。Ci/CD就是自动化作业&#xff0c;实现项目自动编译、发布、执行等&#xff0c;也有用于拉取推送数据的场景。本文主要介绍了在win 11下搭建CI/CD&#xff0c;实现自动…

【JS】事件捕获和事件冒泡的区别

事件捕获和事件冒泡是指在 DOM 树中处理事件时的两种不同的传播方式。它们之间的主要区别在于事件传播的方向和顺序&#xff1a; 事件捕获&#xff08;Capture&#xff09; 方向&#xff1a; 从最外层的祖先元素向目标元素传播。顺序&#xff1a; 事件首先从最外层的祖先元素…

【C++ 面试 - STL】每日 3 题(四)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏&…

[A-08]ARMv8/ARMv9-Memory-内存空间(动态内存控制器与物理内存设备)

ver0.2 更多精彩内容&#xff0c;请关注微信公众号 # 前言 前序的文章中&#xff0c;已经讲解了ARM架构下管理内存的核心组件MMU的相关背景知识。MMU需要借助页表(Translation Table)衔接起虚拟地址空间和物理内存的空间&#xff0c;实现在一个硬件环境下软件任务的并发执行效…

【不安全的集合类】同步容器(如ConcurrentHashMap)、并发集合(如CopyOnWriteArrayList)

文章目录 一、List的线程不安全二、Set的线程不安全三、Map的线程不安全 日常我们用到的集合的情况会很多&#xff0c;在单线程的情况下&#xff0c;不用考虑到线程安全的问题&#xff0c;但是如果在多线程开发的过程中&#xff0c;我们该选择哪一种类型来保证线程安全性呢 &am…

【网络安全】逻辑漏洞:绕过应用程序重要功能

未经许可,不得转载。 文章目录 正文漏洞影响正文 目标:xxx.com 一个流行的汽车平台,允许用户为经销商留下评论。该平台有一个功能,用户可以点赞评论,并且它限制每个用户对每个评论只能点赞一次。 然而,我找到了绕过的方法(并不是并发)。 在点击“点赞”按钮时拦截请…

Python从0到100(五十七):机器学习-主成分分析机

主成分分析是⼀种常⽤的降维技术&#xff0c;⽤于将⾼维数据集投影到低维空间中&#xff0c;同时保留数据集的主要特征。PCA通过寻找数据中最重要的⽅向&#xff08;主成分&#xff09;&#xff0c;并将数据投影到这些⽅向上来实现降维。 1.基本原理 1、数据中心化&#xff1…

linux-squid代理服务器

squid简介 作为应用层的代理服务软件&#xff0c;Squid 主要提供缓存加速、应用层过滤控制的功能、用来缓冲Internet数据 接受来自人们需要下载的目标&#xff08;object&#xff09;的请求并适当地处理这些请求。也就是说&#xff0c;如果想下载一web页面&#xff0c;他请求…

特殊字符合集(包括各种emoji表情、windows ASCII字符、自定义字母图案等)

██████╗███████╗ ██████╗ ██╔════╝╚══███╔╝██╔═══██╗ ███████╗ ███╔╝ ██║ ██║ ╚════██║ ███╔╝ ██║▄▄ ██║ ███████║███████╗╚██████╔╝ ╚══════╝…

【小呆的热力学笔记】典型热机-燃气轮机的理想热力循环

文章目录 6.1 燃气轮机的理想热力循环6.2 燃气轮机理想热力循环热效率分析6.3 燃气轮机的理想热力循环讨论 6.1 燃气轮机的理想热力循环 燃气轮机装置主要包含三个部件&#xff1a;压气机、燃烧室和涡轮&#xff0c;详见下图示意。其中压气机主要有离心式和轴流式两种&#xf…