LeetCode题练习与总结:单词搜索Ⅱ--212

一、题目描述

给定一个 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 * 10^4
  • 1 <= words[i].length <= 10
  • words[i] 由小写英文字母组成
  • words 中的所有字符串互不相同

二、解题思路

这个问题可以使用深度优先搜索(DFS)结合前缀树(Trie)来解决。首先,我们构建一个前缀树,将所有的单词插入到前缀树中。然后,我们遍历二维网格的每一个单元格,从每个单元格开始,使用深度优先搜索在网格中寻找匹配前缀树的单词。

以下是具体的步骤:

  1. 构建前缀树:创建一个Trie类,包含插入和查找方法。将所有的单词插入到前缀树中。

  2. 深度优先搜索:创建一个DFS方法,该方法接受当前单元格的位置、前缀树节点、网格、以及已经访问过的单元格集合。在DFS过程中,如果当前单元格的字符不在前缀树中,返回;否则,检查当前节点是否是一个单词的结尾,如果是,则将该单词添加到结果集中,并从前缀树中删除该单词,以避免重复添加。

  3. 遍历网格:遍历网格的每一个单元格,从每个单元格开始进行DFS搜索。

三、具体代码

class Solution {class TrieNode {TrieNode[] children = new TrieNode[26];String word;}class Trie {TrieNode root = new TrieNode();public void insert(String word) {TrieNode node = root;for (char c : word.toCharArray()) {if (node.children[c - 'a'] == null) {node.children[c - 'a'] = new TrieNode();}node = node.children[c - 'a'];}node.word = word;}}public List<String> findWords(char[][] board, String[] words) {Trie trie = new Trie();for (String word : words) {trie.insert(word);}List<String> res = new ArrayList<>();for (int i = 0; i < board.length; i++) {for (int j = 0; j < board[0].length; j++) {dfs(board, i, j, trie.root, res);}}return res;}private void dfs(char[][] board, int i, int j, TrieNode node, List<String> res) {if (i < 0 || j < 0 || i >= board.length || j >= board[0].length || board[i][j] == '#' || node.children[board[i][j] - 'a'] == null) {return;}char c = board[i][j];node = node.children[c - 'a'];if (node.word != null) {res.add(node.word);node.word = null; // 避免重复添加}board[i][j] = '#'; // 标记为已访问dfs(board, i - 1, j, node, res);dfs(board, i + 1, j, node, res);dfs(board, i, j - 1, node, res);dfs(board, i, j + 1, node, res);board[i][j] = c; // 恢复现场}
}

在上述代码中,我们首先构建了一个Trie树,然后通过DFS在网格中搜索匹配的单词。在DFS过程中,我们使用#字符来标记已经访问过的单元格,以避免重复访问。当一个单词被找到时,我们从Trie树中移除该单词,确保不会重复添加到结果集中。最后,我们恢复单元格的原始字符,以便其他搜索路径可以使用该单元格。

四、时间复杂度和空间复杂度

1. 时间复杂度
  • 构建Trie树:

    • 对于每个单词,我们遍历其所有字符并将其插入到Trie树中。假设单词列表words中总共有N个单词,每个单词的平均长度为L,则构建Trie树的时间复杂度为O(N * L)
  • 深度优先搜索(DFS):

    • 对于网格中的每个单元格,我们可能都会执行一次DFS搜索。网格大小为m * n,每个单元格最多会被访问4次(上、下、左、右)。
    • 在最坏的情况下,每次DFS搜索都会遍历整个网格,即每次DFS的时间复杂度为O(m * n)
    • 因此,所有DFS搜索的总时间复杂度为O(m * n * 4 * m * n),即O(4 * m^2 * n^2),简化后为O(m^2 * n^2)

综上所述,总的时间复杂度为构建Trie树的时间复杂度加上DFS的时间复杂度,即O(N * L + m^2 * n^2)

2. 空间复杂度
  • Trie树:

    • Trie树的空间复杂度取决于单词的数量和长度。在最坏的情况下,如果所有单词都是独特的,Trie树将包含所有单词的字符,空间复杂度为O(N * L)
  • DFS搜索:

    • DFS搜索需要递归栈空间,在最坏的情况下,递归深度为网格大小m * n,因此递归栈空间复杂度为O(m * n)
  • 结果列表:

    • 结果列表存储找到的单词,其空间复杂度取决于找到的单词数量,但不会超过单词列表的总数N,因此空间复杂度为O(N)

综上所述,总的空间复杂度为Trie树的空间复杂度加上DFS递归栈的空间复杂度加上结果列表的空间复杂度,即O(N * L + m * n + N)。由于N * L通常是最大的,因此可以简化为O(N * L)

五、总结知识点

  • 数据结构 - Trie树(前缀树)

    • Trie树是一种用于检索字符串数据集中的键的有序树结构,是一种高效的字符串查找数据结构。
    • 每个节点包含一个字符数组children,用于存储子节点,子节点的索引对应字符与’a’的差值。
    • 每个节点可能包含一个字符串word,用于标记该节点是否是某个单词的结束。
  • 递归 - 深度优先搜索(DFS)

    • DFS是一种用于遍历或搜索树或图的算法。
    • 在DFS中,代码通过递归函数dfs来探索所有可能的路径。
    • DFS的递归终止条件包括越界检查、已访问标记检查以及当前字符是否存在于Trie树中的子节点。
  • 字符串处理

    • 字符串转换为字符数组word.toCharArray(),以便遍历字符串中的每个字符。
    • 字符到索引的转换c - 'a',用于访问Trie树中相应的子节点。
  • 数组操作

    • 使用二维字符数组board表示网格。
    • 数组索引访问,例如board[i][j],用于访问网格中的单元格。
  • 集合操作

    • 使用List<String>来存储找到的单词。
    • 使用ArrayList作为具体的列表实现,提供动态数组的功能。
  • 逻辑控制

    • if语句用于条件判断,例如检查边界条件、字符是否匹配Trie树节点。
    • for循环用于遍历网格的每个单元格和单词列表的每个单词。
  • 标记与恢复

    • 使用特殊字符'#'来标记网格中的单元格已被访问,防止在DFS中重复访问。
    • 在完成当前路径的搜索后,恢复单元格的原始字符,以便其他路径可以使用该单元格。
  • 代码优化

    • 在找到单词后,立即将Trie树中对应节点的word字段设置为null,避免在后续搜索中重复添加相同的单词。

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。

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

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

相关文章

中智科学技术评价研究中心与中企数研究院实现全面合作

8月29日&#xff0c;中智科学技术评价研究中心与《中国企业报》集团数字化发展研究院在北京顺喜山庄成功举办“数字经济GBC生态系统管理平台”项目实施落地座谈会及研究院高层管理集训班&#xff0c;并签署了项目合作协议。此次合作标志着双方将在“数字中国发展战略”的大背景…

人工智能领域正经历模型规模变革,小型语言模型(SLM)崛起,挑战“规模至上”观念。

在人工智能领域&#xff0c;一场关于模型规模的深刻变革正在悄然发生。长久以来&#xff0c;科技巨头们热衷于庞大语言模型&#xff08;LLM&#xff09;的开发竞赛&#xff0c;但如今&#xff0c;小型语言模型&#xff08;SLM&#xff09;正以其独特的优势逐步崭露头角&#xf…

WordNet介绍——一个英语词汇数据库

传统语义知识库最常见的更新方法是依赖人工手动更新&#xff0c;使用这种更新方法的语义知识库包括最早的 WordNet、FrameNet和 ILD&#xff0c;以及包含丰富内容的 ConceptNet和 DBPedia。此类语义知识库的特点是以单词作为语义知识库的基本构成元素&#xff0c;以及使用预先设…

Linux安装Hadoop(单机版)详细教程

目录 一、JDK安装 1、下载JDK安装包 2、解压下载的JDK安装包 3、移动并重命名JDK包 4、配置Java环境变量 5、验证安装是否成功 二、Hadoop安装 1、下载Hadoop安装包 2、解压Hadoop安装包 3、配置Hadoop环境变量 4、修改配置文件 5、验证Hadoop是否安装成功 三&…

代码随想录——回文子串(Leetcode 647)

题目链接 我的题解&#xff08;双指针&#xff09; 思路&#xff1a; 当然&#xff0c;以下是对您提供的代码的解释&#xff1a; class Solution {public int countSubstrings(String s) {// 初始化回文子字符串的数量int count 0;// 遍历字符串的每个字符&#xff0c;使用…

NCH DrawPad Pro for Mac/Win:强大的图像编辑处理软件

NCH DrawPad Pro for Mac/Win是一款功能全面的图像编辑和设计软件&#xff0c;专为Mac和Windows用户设计。它不仅适用于专业设计师&#xff0c;也深受业余爱好者和创意工作者的喜爱。DrawPad Pro凭借其丰富的绘图工具、强大的编辑功能和便捷的模板库&#xff0c;为用户提供了卓…

OpenCV杂项图像变换(2)线性混合函数blendLinear()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 执行两个图像的线性混合&#xff1a; dst ( i , j ) weights1 ( i , j ) ∗ src1 ( i , j ) weights2 ( i , j ) ∗ src2 ( i , j ) \texttt{…

策略模式+模版方法模式+简单工厂模式混用优化代码复杂分支问题

说明 这篇博客是在复杂场景使用策略和工厂模式代替分支语句升级版&#xff0c;增加了模版方法模式。将支付类的公共逻辑抽取到模板类中&#xff0c;使整个支付逻辑更加灵活&#xff0c;进一步优化了代码结构&#xff0c;提升了软件的可维护性和可读性。 流程图如下 先看一遍流…

.NET 多版本兼容的精美 WinForm UI控件库

目录 前言 项目介绍 项目使用 项目源码 项目案例 项目组件 项目地址 前言 有粉丝小伙伴在后台留言咨询有没有WinForm 控件库推荐&#xff0c;现在就给安排上。 .NET 平台进行 Windows 应用程序开发的我们来说&#xff0c;找一个既美观又实用的 WinForm UI 控件库至关重…

STM32通过ADM3222完成UART转232通信电平转换

1、简介 单片机默认串口输出电平是UART信号,但是在实际项目中经常需要将其转换成232电平,此时就需要ADM3222芯片来完成电平的转换,下面对使用过程进行总结。 2、硬件电路 从上图中可以看到芯片需要对1、18进行配置才能进行工作,通过查阅手册可知,1引脚需要配置低电平,…

云计算实训37——Dockerfile的应用+私有仓库的创建与管理

一、文件联合系统 文件联合系统&#xff08;Overlay Filesystem&#xff09;&#xff1a; 是一种允许多个文件系统层叠在一起的文件系统。它通常用于将只读文件系统&#xff08;如基础镜像&#xff09;与可写文件系统&#xff08;如用户的修改&#xff09;结合&#xff0c;形…

【3D目标检测】MMdetection3d——nuScenes数据集训练BEVFusion

引言 MMdetection3d&#xff1a;【3D目标检测】环境搭建&#xff08;OpenPCDet、MMdetection3d&#xff09; MMdetection3d源码地址&#xff1a;https://github.com/open-mmlab/mmdetection3d/tree/main?tabreadme-ov-file IS-Fusion源码地址&#xff1a;https://github.co…

【Scala】Windows下安装Scala(全面)

目录 1.下载 2.安装 3.配置环境变量 1.新增系统环境变量 2.环境变量Path 4.验证 1.下载 官网下载地址&#xff1a;https://downloads.lightbend.com/scala/2.11.12/scala-2.11.12.msi 2.安装 双击下载的.msi文件&#xff1a; 勾选"I accept the terms in the Li…

前后端交互的路径怎么来的?后端解决cors问题的一种方法

背景&#xff1a;后端使用node.js搭建&#xff0c;用的是express 前端请求的路径baseURL怎么来的 &#xff1f; 前后端都在同一台电脑上运行&#xff0c;后端的域名就是localhost&#xff0c;如果使用的是http协议&#xff0c;后端监听的端口号为3000&#xff0c;那么前端请求…

Django+Vue音乐推荐系统的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 需要的环境3.2 Django接口层3.3 实体类3.4 config.ini3.5 启动类3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平台Java领域优质创作者&…

脚手架工具的应用(前端和后端搭建)

前端 一、安装 Node.js 环境 使用npm下载镜像 查看镜像&#xff1a;npm config get registry 切换淘宝镜像&#xff1a;npm config set registry https://registry.npmmirror.com 还原镜像&#xff1a;npm config set registry https://registry.npmjs.org 二、使用 Vue.js 脚…

智能停车场管理小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;车位信息管理&#xff0c;车位预订管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;地图&#xff0c;我的 开发系统&#xff1a;Windows 架构模式…

如何将开发工具设置成滚动鼠标改变字体大小

就在刚刚与温州那边技术开会&#xff0c;温州那边技术提出&#xff1a;字体太小&#xff0c;代码看不清&#xff0c;需要将字体放大。然后让我将IDE设置成按住键盘的Ctrl滚动鼠标&#xff0c;可以放大字体大小。。。顿时间的小小尴尬。下面我来记录一下究竟是怎么操作的&#x…

安装WMware和Ubuntu并使用xShell连接

0、我的电脑配置 设备名称 hello 处理器 Intel(R) Core(TM) i7-10700K CPU 3.80GHz 3.79 GHz 机带 RAM 16.0 GB (15.9 GB 可用) 设备 ID 541EC230-9910-418C-9043-5FBBF8ED320C 产品 ID 00330-80000-00000-AA846 系统类型 64 位操作系统, 基于 x64 的处理器 笔和触控 没有可…

汽车功能安全--TC3xx LBIST触发时机讨论

目录 1. LBIST架构 2. LBIST寄存器配置 3. LBIST触发时机 LBIST&#xff0c;全称Logic Built-in Self Test。 在TC3xx中&#xff0c;LBIST是一种硬件功能安全机制&#xff0c;目的是为了探测MCU内部逻辑电路的潜伏故障(latent faults)。 从使用者角度来看&#xff0c;只需…