剑指Offer12.矩阵中的路径 C++

1、题目描述

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

例如,在下面的 3×4 的矩阵中包含单词 “ABCCED”(单词中的字母已标出)。
在这里插入图片描述
示例 1
输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCCED”
输出:true
示例 2
输入:board = [[“a”,“b”],[“c”,“d”]], word = “abcd”
输出:false

2、VS2019上运行

使用回溯的方法

#include <iostream>
#include <vector>
using namespace std;

class Solution {
public:
    bool check(vector<vector<char>>& board, vector<vector<int>>& visited, int i, int j, string& s, int k) {
        // 检查当前坐标的字母是否与目标单词中的对应字母相等
        if (board[i][j] != s[k]) {
            return false;
        }
        // 如果已经匹配到目标单词的最后一个字母,表示找到了路径,返回true
        else if (k == s.length() - 1) {
            return true;
        }

        visited[i][j] = true; // 将当前坐标标记为已访问
        vector<pair<int, int>> directions{ {0, 1}, {0, -1}, {1, 0}, {-1, 0} }; // 上、下、左、右四个方向

        bool result = false; // 用于记录是否找到路径

        // 依次遍历四个方向
        for (const auto& dir : directions) {
            int newi = i + dir.first, newj = j + dir.second; // 计算新坐标
            // 检查新的坐标是否在矩阵范围内且没有被访问过
            if (newi >= 0 && newi < board.size() && newj >= 0 && newj < board[0].size()) {
                if (!visited[newi][newj]) {//用于检查位置(newi, newj)是否已经被访问过
                    // 递归调用check函数进行下一步的搜索
                    bool flag = check(board, visited, newi, newj, s, k + 1);
                    if (flag) {
                        result = true; // 如果找到路径,直接返回true
                        break;
                    }
                }
            }
        }

        visited[i][j] = false; // 撤销对当前坐标的标记
        return result;
    }

    bool exist(vector<vector<char>>& board, string word) {
        int h = board.size(), w = board[0].size(); // 矩阵的行数和列数
        vector<vector<int>> visited(h, vector<int>(w)); // 记录每个格子的访问状态

        // 遍历矩阵的每个格子,对每个格子调用check函数
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                bool flag = check(board, visited, i, j, word, 0); // 调用check函数进行搜索
                if (flag) {
                    return true; // 如果找到路径,直接返回true
                }
            }
        }

        return false; // 遍历结束后仍未找到路径,返回false
    }
};

int main() {
    // 示例用法
    vector<vector<char>> board = {
        {'A', 'B', 'C', 'E'},
        {'S', 'F', 'C', 'S'},
        {'A', 'D', 'E', 'E'}
    };

    Solution s;
    string word = "ABCCED";

    if (s.exist(board, word)) {
        cout << "Word exists in the board." << endl;
    }
    else {
        cout << "Word does not exist in the board." << endl;
    }

    return 0;
}

Word exists in the board.

3、整体思路

整体的思路是使用深度优先搜索(DFS)算法在矩阵中搜索是否存在与目标单词匹配的路径。

  • 首先,定义一个 check 函数来进行递归的搜索。该函数接收当前的坐标 (i, j)、目标单词 s、以及目前匹配的字符索引 k。函数的返回值是一个布尔值,表示是否找到了匹配的路径。
  • 在 check 函数中,首先进行边界条件的判断。如果当前索引 k 已经匹配到目标单词的最后一个字符,说明已经找到了匹配的路径,返回 true。
  • 接下来,检查当前坐标 (i, j) 处的字母是否与目标单词中的对应字母相等。如果不相等,说明当前路径匹配失败,返回 false。
  • 检查新坐标是否在矩阵的范围内,并且该位置没有被访问过(即 visited[newi][newj] = false)。
    如果满足上述条件,则递归调用 check 函数,在新坐标 (newi, newj) 上继续匹配下一个字符,即 k + 1。
  • 如果递归调用返回 true,表示在某个方向上找到了匹配的路径,直接返回 true。
    如果所有方向的递归调用都没有找到匹配的路径,则撤销对当前坐标 (i, j) 的标记,将 visited[i][j] 设置为 false,表示可以重新访问该位置。
  • 最后,如果所有方向都探索完毕,仍然没有找到匹配的路径,则返回 false,表示没有找到路径。
  • 接下来可以调用 check 函数,从矩阵的每个位置出发,判断是否存在与目标单词匹配的路径。如果返回 true,则说明存在这样的路径;如果返回 false,则说明不存在。
  • 这就是整体的思路,通过DFS算法搜索矩阵中的路径,并利用递归和回溯的思想进行搜索和撤销标记。

4、int h = board.size(), w = board[0].size();

  • 这行代码int h = board.size(), w = board[0].size();的作用是获取二维字符向量board的行数h和列数w。
  • 1.board.size()返回二维字符向量board的行数,即向量中包含的子向量个数。
    2.board[0].size()返回二维字符向量board中第一行子向量的列数,假设矩阵不为空。

5、vector<vector> visited(h, vector(w));

  • 这行代码vector<vector<int>> visited(h, vector<int>(w));创建了一个名为visited的二维整数向量,其大小与输入矩阵board的行数和列数相同。
  • 1.vector<int>(w)部分创建了一个大小为w的整数向量。
  • 2.vector<vector<int>> visited(h, vector<int>(w));使用上述创建的子向量为每一行创建了一个整数向量,从而形成了一个大小为h行、w列的二维整数向量visited。
  • 这样的二维向量visited可以用于跟踪和记录在处理board矩阵时已经访问过的位置或标记。

6、dir.first 和dir.second

  • dir.first表示dir这个pair(键值对)中的第一个元素,即表示方向的行坐标变化。在该上下左右的方向向量中,dir.first表示上下移动的行坐标的变化量。
  • 例如,如果dir是(-1, 0),那么dir.first就是-1,表示向上移动1行。同理,如果dir是(1, 0),那么dir.first就是1,表示向下移动1行。
  • 在搜索一个矩阵的周围方向时,dir.first的值用于计算新的行坐标。通过将当前位置的行坐标i与dir.first相加,可以得到新的行坐标,用于在矩阵中检查相邻位置是否符合要求。

7、visited[i][j] = false;

  • 这行代码为撤销对当前坐标(i, j)的访问标记,将其重新设置为false。
  • 标记的目的是为了跟踪遍历矩阵时已经访问过的位置,以避免重复访问。在代码中,visited向量用于标记位置是否已经被访问过。
  • 当程序进行完成对位置(i, j)的处理后,如果希望在后续的搜索或迭代中能够重新访问该位置,就需要撤销对该位置的访问标记,将visited[i][j]重新设置为false。
  • 撤销对当前坐标的标记允许在后续的遍历或搜索过程中重新考虑访问该位置,以发现其他可能的路径或结果。如果不撤销标记的话,可能会导致某些位置被错误地标记为已访问,从而错过了找到其他路径或结果的机会。因此,需要在适当的时候撤销对当前坐标的标记。

8、for (const auto& dir : directions)

  • for (const auto& dir : directions) 是一个范围-based的循环语句,用于遍历容器 directions 中的元素。
  • 在这个语句中,dir 是一个临时变量,它会依次取到 directions 中的每个元素值。关键字 auto 会自动推断 dir 的类型,使其与 directions 中的元素类型保持一致。const 修饰符表示 dir 是一个常量,即在循环体内不能对它进行修改。
  • 通过这个循环语句,可以依次遍历 directions 容器中的每个方向,执行相应的操作,如计算新坐标 (newi, newj),进行路径匹配等。这样可以依次尝试不同的方向,以搜索矩阵中是否存在与目标单词匹配的路径。

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

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

相关文章

关于Express 5

目录 1、概述 2、Express 5的变化 2.1 弃用或删除内容的列表&#xff1a; app.param&#xff08;name&#xff0c;fn&#xff09;名称中的前导冒号&#xff08;&#xff1a;&#xff09; app.del() app.param&#xff08;fn&#xff09; 复数方法名 res.json&#xff0…

Python批量查字典和爬取双语例句

最近&#xff0c;有网友反映&#xff0c;我的批量查字典工具换到其它的网站就不好用了。对此&#xff0c;我想说的是&#xff0c;互联网包罗万象&#xff0c;网站的各种设置也有所不同&#xff0c;并不是所有的在线字典都可以用Python爬取的。事实上&#xff0c;很多网站为了防…

计算机是怎么存储和识别人类高级语言的

目录 1、计算机是怎么“存储”人类的高级语言的&#xff1f;2、 UTF-8和UTF-32的区别3、UTF-8是如何区分字节的长度呢&#xff1f;&#xff08;即如何识别这一串二进制是多少个字节的&#xff1f;&#xff09;4、计算机是如何识别人类的高级语言的&#xff1f; 1、计算机是怎么…

八、复用(1)

本章概要 组合语法继承语法 初始化基类带参数的构造函数 委托 代码复用是面向对象编程&#xff08;OOP&#xff09;最具魅力的原因之一。 对于像 C 语言等面向过程语言来说&#xff0c;“复用”通常指的就是“复制代码”。任何语言都可通过简单复制来达到代码复用的目的&#…

使用JProfiler进入JVM分析

要评测JVM&#xff0c;必须将JProfiler的评测代理加载到JVM中。这可以通过两种不同的方式发生&#xff1a;在启动脚本中指定-agentpath VM参数&#xff0c;或者使用attach API将代理加载到已经运行的JVM中。 JProfiler支持这两种模式。添加VM参数是评测的首选方式&#xff0c;集…

【MMU】认识 MMU 及内存映射的流程

MMU&#xff08;Memory Manager Unit&#xff09;&#xff0c;是内存管理单元&#xff0c;负责将虚拟地址转换成物理地址。除此之外&#xff0c;MMU 实现了内存保护&#xff0c;进程无法直接访问物理内存&#xff0c;防止内存数据被随意篡改。 目录 一、内存管理体系结构 1、…

openssl安装问题合辑

1.openssl拖累nginx编译失败 问题描述&#xff1a; 因为漏洞原因&#xff0c;升级openssl之后需要重新编译nginx&#xff0c;进行了以下步骤&#xff1a; config没问题&#xff0c;但是make一直报错 初步判断是openssl安装有问题&#xff0c;原因不明&#xff0c;重装了opens…

Java后台生成ECharts图片

前言 通过echarts的jar包&#xff0c;Java后台生成一张图片&#xff0c;并把图片插入到word中。关于word插图片的代码在下一章。 需要用到的工具PhantomJS,Echarts-convert.js,jquery.js,echarts.js。 1.PhantomJS 介绍 PhantomJS是一个不需要浏览器的富客户端。 官方介绍&…

第八章:Linux信号

系列文章目录 文章目录 系列文章目录前言linux中的信号进程对信号的处理信号的释义 信号的捕捉信号的捕捉signal()信号的捕捉sigaction() 信号的产生通过终端按键产生信号前台进程与后台进程 kill()用户调用kill向操作系统发送信号raise()进程自己给自己发任意信号&#xff08;…

利用Google Docs的评论功能投递钓鱼链接

情报背景 利用Google drive等可信云服务进行的网络钓鱼攻击活动日益增长&#xff0c;这种攻击手段利用了高可信度的云服务骗取受害者的信任&#xff0c;并且可以绕过基于域名的安全策略。 近期Avanan公司发现了一种新的邮件钓鱼方式&#xff0c;攻击者利用Google docs的评论功…

计蒜客T1115——字符串判等

水题不解释&#xff0c;考研复习压力偶尔写一道换换心情还不错~ 这里有一个比较有趣的知识点&#xff0c;对于同时输入多个字符串时还要允许空格的输入&#xff0c;那么普通的cin函数就不能满足要求了&#xff0c;这里采用getline函数解决&#xff0c;如下&#xff1a; string …

使用最新技术实现智能考试系统源码

智能考试系统是一种重要的教育技术应用&#xff0c;它能够通过结合计算机科学和教育理论&#xff0c;为教育工作者提供一个高效、灵活和可靠的考试平台。最近&#xff0c;随着人工智能和大数据技术的飞速发展&#xff0c;智能考试系统受到了越来越多的关注。本文将详细介绍如何…

接口测试如何在json中引用mock变量

在测试接口的时候&#xff0c;有的接口需要测试随机传入大量数据&#xff0c;查看数据库是否正常&#xff0c;但是大量的随机数据全靠自己手写会很慢&#xff0c;而且是通过json传递的数据。 这里我们就可以使用mock生成随机变量&#xff0c;然后在json中引用mock变量 首先看…

ElasticSearch 7.4学习记录(基础概念和基础操作)

若你之前从未了解过ES&#xff0c;本文将由浅入深的一步步带你理解ES&#xff0c;简单使用ES。作者本人就是此状态&#xff0c;通过学习和梳理&#xff0c;产出本文&#xff0c;已对ES有个全面的了解和想法&#xff0c;不仅将知识点梳理&#xff0c;也涉及到自己的理解&#xf…

vue3:新特性

一、react和vue的主要区别 &#xff08;1&#xff09;数据更新上&#xff1a; 1、 react 采用 fiber架构 &#xff0c;使用 链表 表示 DOM 结构可以在 diff 时随时中断和继续&#xff0c;利用requestIdleCallback 在空闲时 diff &#xff0c;防止数据量大 diff 时间长导致卡顿…

线程池-手写线程池C++11版本(生产者-消费者模型)

本项目是基于C11的线程池。使用了许多C的新特性&#xff0c;包含不限于模板函数泛型编程、std::future、std::packaged_task、std::bind、std::forward完美转发、std::make_shared智能指针、decltype类型推断、std::unique_lock锁等C11新特性功能。 本项目有一定的上手难度。推…

【Linux升级之路】5_基础IO

&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#x1f31f; &#x1f36d;&#x1f36d;系列专栏&#xff1a;【Linux升级之路】 ✒️✒️本篇内容&#xff1a;文件操作&#xff0c;文件管理&#xff0c;重定向&#xff0c;简易shell添加重定向功能&#xff0c;文件属…

人物启示-张一鸣与陆奇

在科技行业中&#xff0c;张一鸣与陆奇可谓是两位颇具影响力的人物。张一鸣和陆奇分别是字节跳动&#xff08;TikTok 的母公司&#xff09;的创始人和百度前总裁。张一鸣作为字节跳动的创始人&#xff0c;成功打造了今日头条、抖音等知名产品&#xff0c;而陆奇则曾任微软副总裁…

Django Rest_Framework(二)

文章目录 1. http请求响应1.1. 请求与响应1.1.1 Request1.1.1.1 常用属性1&#xff09;.data2&#xff09;.query_params3&#xff09;request._request 基本使用 1.1.2 Response1.1.2.1 构造方式1.1.2.2 response对象的属性1&#xff09;.data2&#xff09;.status_code3&…

4G型无线液位变送器是什么?

4G型无线液位变送器采用了四代无线通讯技术&#xff0c;与普通液位计相比&#xff0c;免去了布线的烦恼&#xff0c;无需时刻监控现场&#xff0c;在大幅提高工作效率和减少人力成本的同时&#xff0c;还可以随时随地获取监测数据。 4G型无线液位变送器的功能优势&#xff1a;…