leetcode212. 单词搜索 II

给定一个 m x n 二维字符网格 board 和一个单词(字符串)列表 words, 返回所有二维网格上的单词 。

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

示例 1:

输入:board = [["o","a","a","n"],["e","t","a","e"],["i","h","k","r"],["i","f","l","v"]], words = ["oath","pea","eat","rain"]
输出:["eat","oath"]

示例 2:

输入:board = [["a","b"],["c","d"]], words = ["abcb"]
输出:[]

提示:

  • m == board.length
  • n == board[i].length
  • 1 <= m, n <= 12
  • board[i][j] 是一个小写英文字母
  • 1 <= words.length <= 3 * 104
  • 1 <= words[i].length <= 10
  • words[i] 由小写英文字母组成
  • words 中的所有字符串互不相同

解题分析

问题性质定义
  • 输入:

    1. 一个二维字符网格 board,大小为 m×nm \times n。
    2. 一个单词列表 words
  • 输出:所有可以在网格上找到的单词列表。

  • 限制条件

    1. 单词必须按相邻单元格顺序构成,单元格可以水平或垂直相邻。
    2. 同一单元格内的字母不能重复使用。
    3. 单词列表中的单词互不相同。
  • 边界条件

    1. 空单词列表 words 或空字符网格 board
    2. 网格很大 m,n≤12m, n \leq 12,单词列表很长 ∣words∣≤3×10^4,需要设计高效算法。
    3. 单词可能部分匹配(前缀匹配),但需要完整匹配才能算找到。

解决思路

  1. 算法设计

    • 前缀树 (Trie):构建 Trie 存储单词列表以高效地支持前缀匹配,避免无效搜索。
    • 深度优先搜索 (DFS):从每个网格单元格出发,尝试通过 DFS 查找单词,同时避免重复访问。
    • 剪枝优化
      • 如果当前路径不匹配任何 Trie 前缀,立即停止搜索。
      • 使用标志位标记访问过的单元格。
  2. 时间复杂度分析

    • 构建 Trie:O(L),其中 L 是 words 中所有单词长度总和。
    • 搜索:对于每个单元格,最差情况下搜索整棵 Trie,时间复杂度为 O(m×n×4k),其中 k 是单词的最大长度。
    • 总复杂度:结合 Trie 的剪枝优化,实际效率远优于暴力搜索。
  3. 空间复杂度

    • Trie 的空间复杂度为 O(L)。
    • 递归栈深度为单词的最大长度 O(k)。
  4. C++ 实现
// Trie 节点定义
struct TrieNode {unordered_map<char, TrieNode*> children;string word = "";  // 保存单词末尾
};// 构建 Trie
class Trie {
public:TrieNode* root;Trie() {root = new TrieNode();}void insert(const string& word) {TrieNode* node = root;for (char c : word) {if (!node->children.count(c)) {node->children[c] = new TrieNode();}node = node->children[c];}node->word = word;  // 在单词结尾保存整个单词}
};class Solution {
public:vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {vector<string> result;Trie trie;// 1. 将所有单词插入 Triefor (const string& word : words) {trie.insert(word);}// 2. 遍历网格,进行深度优先搜索int m = board.size(), n = board[0].size();for (int i = 0; i < m; ++i) {for (int j = 0; j < n; ++j) {dfs(board, i, j, trie.root, result);}}return result;}private:void dfs(vector<vector<char>>& board, int i, int j, TrieNode* node, vector<string>& result) {char c = board[i][j];// 剪枝:超出边界或当前字符不在 Trie 中if (c == '#' || !node->children.count(c)) {return;}node = node->children[c];// 如果找到单词,加入结果集if (!node->word.empty()) {result.push_back(node->word);node->word = "";  // 避免重复添加}// 标记当前单元格为已访问board[i][j] = '#';// 递归搜索四个方向int directions[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};for (auto& dir : directions) {int x = i + dir[0], y = j + dir[1];if (x >= 0 && x < board.size() && y >= 0 && y < board[0].size()) {dfs(board, x, y, node, result);}}// 恢复当前单元格board[i][j] = c;// 优化:如果当前 Trie 节点无子节点,删除它if (node->children.empty()) {node = nullptr;}}
};

代码详细解释

  1. Trie 的构建

    • 使用 Trie 存储单词列表,便于高效的前缀匹配。
    • 每个节点存储其子节点映射和一个 word 字符串,用于标记该节点是否是某个单词的末尾。
  2. DFS 搜索

    • 从网格中每个单元格出发,尝试匹配 Trie 中的单词。
    • 剪枝条件:
      • 当前字符不在 Trie 中。
      • 当前单元格已访问(用 # 标记)。
    • 匹配到单词后,立即加入结果集,并将该单词从 Trie 中删除(防止重复匹配)。
    • 搜索四个方向的邻居单元格。
  3. 优化

    • 标记访问过的单元格,避免重复路径。
    • 当某个 Trie 节点的 children 为空时,提前释放内存。

启发与实际应用

启发:
  • Trie 结合 DFS 是解决字符串匹配问题的经典方法,特别适合大规模、多前缀的单词匹配场景。
  • 剪枝优化和内存管理在搜索问题中至关重要,可以极大提升性能。
实际应用:
  • 拼写检查:在输入法、文本编辑器中高效匹配单词。
  • 词频分析:在网格状数据中统计出现的关键词。
  • 游戏开发:如文字搜索游戏,可以快速匹配玩家找到的单词。
示例场景:

输入法联想

  • 需求:用户输入拼音或字母时,联想出可能的候选词。
  • 实现
    • 使用 Trie 存储所有词典。
    • 用户输入字符时,从 Trie 中按前缀查找所有匹配单词。
    • 联想结果按词频排序,实时显示给用户。

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

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

相关文章

容器化技术

文章目录 虚拟化容器容器隔离实现隔离文件 chroot隔离访问 namespace隔离资源 cgroups Dockerkubernetes 虚拟化容器 容器的首要目标是让软件分发部署过程从传统的发布安装包、靠人工部署转变为直接发布已经部署好的、包含整套运行环境的虚拟计划镜像。 一个计算机软件能够给正…

【潜意识Java】javaee中的SpringBoot在Java 开发中的应用与详细分析

目录 一、前言 二、Spring Boot 简介 三、Spring Boot 核心模块 四、Spring Boot 项目实战&#xff1a;构建一个简单的 RESTful API 1. 创建 Spring Boot 项目 2. 配置数据库 3. 创建实体类 4. 创建 JPA 仓库接口 5. 创建服务层 6. 创建控制器层 7. 测试 API 8. 运…

土地档案管理关系[源码+文档]

目录 摘 要 Abstract 1 绪论 1.1 可行性研究编写目的 1.2 项目背景 1.3 土地管理现状 1.4 土地档案管理研究方向 1.5 项目目标 1.6 项目设计原则 1.6.1 实用性原则 1.6.2 经济性原则 1.6.3 合法性原则 2 相关技术介绍 2.1 三层架构的选择 2.2 编程…

使用C语言编写UDP循环接收并打印消息的程序

使用C语言编写UDP循环接收并打印消息的程序 前提条件程序概述伪代码C语言实现编译和运行C改进之自由设定端口注意事项在本文中,我们将展示如何使用C语言编写一个简单的UDP服务器程序,该程序将循环接收来自指定端口的UDP消息,并将接收到的消息打印到控制台。我们将使用POSIX套…

Audiocraft智能音频和音乐生成工具部署及使用

1、概述 Facebook开源了一款名为AudioCraft的AI音频和音乐生成工具。 该工具可以直接从文本描述和参考音乐生成高质量的音频和音乐。AudioCraft包含MusicGen、AudioGen和EnCodec三个模型&#xff0c;分别实现音乐生成、音频生成和自定义音频模型构建。 2、项目地址 https://…

vulnhub靶场【DriftingBlues】之7

前言 靶机&#xff1a;DriftingBlues-6&#xff0c;IP地址192.168.1.65 攻击&#xff1a;kali&#xff0c;IP地址192.168.1.16 都采用虚拟机&#xff0c;网卡为桥接模式 主机发现 使用arp-scan -l或netdiscover -r 192.168.1.1/24 信息收集 使用nmap扫描端口 SSH服务&…

SCAU期末笔记 - Linux系统应用与开发教程样卷解析(2024版)

我真的不理解奥&#xff0c;为什么会有给样卷不自带解析的&#xff0c;对答案都没得对&#xff0c;故整理一篇 样卷1 一、选择题 1、为了遍历shell脚本调用时传入的参数&#xff0c;需要在shell脚本中使用_____。 A.$#表示参数的个数B.S表示所有参数C.$0表示脚本名D.$1表示…

spring\strust\springboot\isp前后端那些事儿

后端 一. 插入\更新一条数据&#xff08;老&#xff09; Map<String, Object> parameterMap MybatisUtil.initParameterSave("Send_ProjectFrozenLog", sendProjectFrozenLog); commonMapper.insert(parameterMap);parameterMap MybatisUtil.initParameter…

对golang的io型进程进行off-cpu分析

背景&#xff1a; 对于不能占满所有cpu核数的进程&#xff0c;进行on-cpu的分析是没有意义的&#xff0c;因为可能程序大部分时间都处在阻塞状态。 实验例子程序&#xff1a; 以centos8和golang1.23.3为例&#xff0c;测试下面的程序&#xff1a; pprof_netio.go package m…

CSS Grid 布局:属性及使用详解

CSS Grid 布局&#xff1a;属性及使用详解 一、CSS Grid 布局的基础概念二、主要的 CSS Grid 属性1、display: grid / display: inline-grid声明 Grid 容器2、grid-template-columns / grid-template-rowsGrid 容器中列和行的尺寸3、 grid-template-areas命名布局区域4、gap/ g…

【数学建模】利用Matlab绘图(2)

一、Matlab中plot函数的基本用法 在matlab中&#xff0c;函数的基本用法主要包括以下几种 第一类&#xff1a; plot(X,Y,LineSpec) 第二类&#xff1a; plot(tbl,xvar,yvar) 1.1 第一类 1.1.1x-y坐标 x和y的选择取决于绘图所需的数据类型以及图像的类型。下表列出了几种…

编写工具模块

文章目录 1.新建模块1.新建模块sun-common-tool2.sun-dependencies指定依赖3.sun-common统一管理sun-common-tool子模块4.sun-common-tool的pom.xml5.清除掉创建模块时默认sun-frame对sun-common-tool进行管理 2.常用工具类1.DateUtils.java2.EncodeUtils.java3.IpUtils.java4.…

构建一个rust生产应用读书笔记四(实战3)

从这一节开始&#xff0c;我们将继续完善邮件订阅生产级应用&#xff0c;根据作者的选型sqlx作为数据库操作的类库&#xff0c;它有如下优点&#xff1a; 它旨在提供高效、安全且易于使用的数据库交互体验。sqlx 支持多种数据库&#xff0c;包括 PostgreSQL、MySQL 和 SQLite&…

视频直播点播平台EasyDSS推拉流技术结合无人机推流在道路交通巡检场景中的应用

随着城市化进程的加速&#xff0c;交通网络日益复杂&#xff0c;交通巡检工作面临着前所未有的挑战。传统的巡检方式往往依赖于人工巡查或地面监控设备&#xff0c;但这些方法存在巡检范围有限、效率低下等缺点。 无人机凭借其高空视野、灵活机动、实时监控等优势&#xff0c;…

VBA技术资料MF238:ADO提取多文件区域指定数据到工作表

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

Mapper代理开发

引入 Mybatis入门方式中&#xff0c;以下代码仍存在硬编码问题 Mapper 代理开发&#xff1a; 目的&#xff1a; 解决原生方式中的硬编码 简化后期执行sql ------下图中&#xff0c;第一段代码是原生硬编码代码块&#xff0c;第二个是引入了Mapper代理开发的代码块。 Mapper代…

ubuntu22.04编译安装Opencv4.8.0+Opencv-contrib4.8.0教程

本章教程,主要记录在Ubuntu22.04版本系统上编译安装安装Opencv4.8.0+Opencv-contrib4.8.0的具体过程。 一、下载opencv和opencv-contrib包 wget https://github.com/opencv/opencv/archive/refs/tags/4.8.0.zip wget https://github.com/opencv/opencv_contrib/archive/refs/…

使用C语言连接MySQL

库的准备 要使用C语言连接mysql&#xff0c;需要使用mysql官网提供的connect库&#xff0c;可以去官网下载&#xff0c;由于我们要下载到 Linux 操作系统中&#xff0c;也可以使用如下指令进行安装库 sudo apt-get install libmysqlclient-dev MySQL连接C/C的库通常会安装在/us…

【Android学习】RxJava

文章目录 资料连接1. Merge & Zip操作符: 合并数据源2. Map & FlapMap & ConcatMap & Buffer: 变换操作符3. retry & retryUntil & retryWhen : 错误处理操作符4. Transformer & Compose 转换操作符5. 网络请求嵌套回调 FlatMap6. 网络请求出错重连…

Mac配置 Node镜像源的时候报错解决办法

在Mac电脑中配置国内镜像源的时候报错,提示权限问题,无法写入配置文件。本文提供解决方法,青测有效。 一、原因分析 遇到的错误是由于 .npm 目录下的文件被 root 用户所拥有,导致当前用户无法写入相关配置文件。 二、解决办法 在终端输入以下命令,输入管理员密码即可。 su…