LeetCode 212题解析:Trie树优化单词搜索II算法
1. 问题背景与核心挑战LeetCode 212题单词搜索II是一个经典的二维网格搜索问题要求在一个字符矩阵中找到所有出现在给定词典中的单词。这个问题看似简单但实际上面临几个关键挑战首先直接使用暴力搜索对每个单词单独执行单词搜索I的解法时间复杂度会非常高。假设网格大小为M×N词典包含K个单词平均单词长度为L那么时间复杂度将达到O(K×M×N×4^L)。当K较大时比如10^4量级这种解法在LeetCode上会直接超时。其次我们需要处理前缀重叠的情况。比如词典中包含apple和applet这两个单词有共同前缀appl。如果分别搜索这两个单词会重复计算前缀路径造成大量冗余计算。最后矩阵中的字符可能重复使用同一个单元格在不同单词中可以重复使用但在同一个单词中不能重复使用这要求我们在搜索过程中维护访问状态同时要确保状态回溯正确。2. Trie树前缀树解决方案2.1 Trie树数据结构设计Trie树是解决这个问题的关键数据结构。它能够高效处理具有公共前缀的字符串集合将搜索时间复杂度从O(K×L)降低到O(L)其中L是单词的平均长度。class TrieNode { MapCharacter, TrieNode children new HashMap(); String word null; // 非null表示这是一个单词的结束节点 }这个设计有几个关键点使用Map而不是固定大小的数组来存储子节点节省空间word字段双重作用既标记单词结束又直接存储完整单词避免回溯拼接没有单独的isEnd标志用word!null隐含表示2.2 Trie树的构建构建Trie树的过程就是把所有单词插入到树中的过程private void insertWord(TrieNode root, String word) { TrieNode node root; for (char c : word.toCharArray()) { if (!node.children.containsKey(c)) { node.children.put(c, new TrieNode()); } node node.children.get(c); } node.word word; // 在结尾节点存储完整单词 }构建时间复杂度是O(K×L)其中K是单词数量L是平均长度。虽然需要额外空间存储Trie树但相比暴力解法的时间优化这个空间开销是值得的。3. 回溯搜索算法实现3.1 主算法框架public ListString findWords(char[][] board, String[] words) { ListString result new ArrayList(); TrieNode root buildTrie(words); for (int i 0; i board.length; i) { for (int j 0; j board[0].length; j) { dfs(board, i, j, root, result); } } return result; }主算法分为三步构建Trie树遍历矩阵每个位置作为起点对每个起点执行DFS搜索3.2 DFS搜索实现细节DFS实现有几个关键点需要注意private void dfs(char[][] board, int i, int j, TrieNode node, ListString result) { char c board[i][j]; if (!node.children.containsKey(c)) return; TrieNode nextNode node.children.get(c); if (nextNode.word ! null) { // 找到一个单词 result.add(nextNode.word); nextNode.word null; // 去重避免重复添加 } board[i][j] #; // 标记已访问 // 四个方向搜索 if (i 0) dfs(board, i-1, j, nextNode, result); if (j 0) dfs(board, i, j-1, nextNode, result); if (i board.length-1) dfs(board, i1, j, nextNode, result); if (j board[0].length-1) dfs(board, i, j1, nextNode, result); board[i][j] c; // 回溯 }关键优化点直接在Trie节点中存储完整单词找到后直接加入结果避免回溯拼接找到单词后将word字段置为null避免重复添加同一单词使用原位标记法修改board矩阵记录访问状态比额外维护visited数组更高效搜索前先检查子节点是否存在避免不必要的递归4. 性能优化与边界处理4.1 剪枝策略在实际实现中可以添加几个重要的剪枝优化子节点剪枝当某个Trie节点的children为空时可以直接从Trie树中移除该节点。因为后续搜索不可能通过这个节点找到任何单词。if (nextNode.children.isEmpty()) { node.children.remove(c); // 剪枝 }结果去重题目可能包含重复单词需要在插入Trie树前先对words数组去重。提前终止当结果集大小等于words数组长度时可以提前终止所有搜索。4.2 边界条件处理需要特别注意的边界情况包括空矩阵或空单词列表矩阵中所有字符相同且单词也全部相同单词长度超过矩阵总格子数单词包含矩阵中不存在的字符5. 复杂度分析5.1 时间复杂度构建Trie树O(K×L)K是单词数量L是平均长度搜索过程最坏情况下需要遍历矩阵每个位置(M×N)每个位置最坏搜索深度为最长单词长度L所以是O(M×N×4^L)但实际由于Trie树的剪枝效果平均情况会好很多。特别是当矩阵中不存在某些字符时相关路径会被快速剪掉。5.2 空间复杂度Trie树空间O(K×L)递归栈深度O(L)结果列表O(K)总空间复杂度是O(K×L)主要由Trie树决定。6. 实际编码中的常见问题6.1 内存溢出问题当单词列表非常大时比如10^5量级标准的Trie树实现可能会导致内存不足。可以考虑以下优化使用更紧凑的Trie树实现比如Ternary Search Tree对单词列表按长度分组先搜索短单词利用剪枝减少长单词搜索范围使用迭代而非递归实现DFS避免栈溢出6.2 多线程优化对于特别大的矩阵可以考虑将矩阵分块每个块由一个线程处理// 伪代码示例 ExecutorService executor Executors.newFixedThreadPool(4); ListFutureListString futures new ArrayList(); for (int block 0; block 4; block) { final int startRow block * rows / 4; final int endRow (block 1) * rows / 4; futures.add(executor.submit(() - { ListString localResult new ArrayList(); for (int i startRow; i endRow; i) { for (int j 0; j cols; j) { dfs(board, i, j, root, localResult); } } return localResult; })); } // 合并结果...注意需要保证Trie树的线程安全或者每个线程使用Trie树的副本。7. 算法扩展与变种7.1 支持通配符搜索如果需要支持.通配符匹配任意字符只需修改Trie树的搜索逻辑if (c .) { for (TrieNode child : node.children.values()) { dfs(board, i, j, child, result); } } else { // 原有逻辑 }7.2 寻找最长单词在搜索过程中可以维护一个最大长度变量或者对单词列表按长度降序排序找到第一个有效单词后即可停止搜索。7.3 单词出现次数统计如果需要统计每个单词出现的次数允许重叠可以修改Trie节点class TrieNode { MapCharacter, TrieNode children new HashMap(); int count 0; // 单词出现次数 }并在找到单词时递增count而不是设置word字段。8. 测试用例设计完整的解决方案应该通过以下测试用例常规情况char[][] board { {o,a,a,n}, {e,t,a,e}, {i,h,k,r}, {i,f,l,v} }; String[] words {oath,pea,eat,rain}; // 预期输出: [eat,oath]重复单词String[] words {oath,oath,eat}; // 应只输出一次oath空输入char[][] board {}; String[] words {test}; // 预期输出: []全相同字符char[][] board { {a,a}, {a,a} }; String[] words {aaaa,aa,a}; // 预期输出所有单词单词不在矩阵中String[] words {xyz,abcd}; // 预期输出: []9. 与其他解法的对比9.1 与暴力解法的对比暴力解法对每个单词单独执行单词搜索I的解法时间复杂度O(K×M×N×4^L)空间复杂度O(L)递归深度优点实现简单无需额外数据结构缺点无法处理大规模单词列表Trie树解法时间复杂度O(M×N×4^L K×L)空间复杂度O(K×L)优点高效处理公共前缀适合大规模单词列表缺点实现复杂需要额外空间9.2 与哈希集合解法的对比另一种思路是先用所有单词构建哈希集合然后在DFS过程中收集潜在字符串查询哈希集合时间复杂度O(M×N×4^L×L)每次查询哈希需要O(L)空间复杂度O(K×L)优点实现简单缺点无法利用前缀信息性能较差10. 实际工程中的应用这种Trie树结合回溯的算法模式在实际工程中有广泛应用搜索引擎的自动补全功能拼写检查与单词建议DNA序列匹配路由表的最长前缀匹配输入法的词库检索在这些场景中数据规模往往比LeetCode题目大得多因此还需要考虑以下工程优化磁盘存储的Trie树结构分布式Trie树查询增量更新Trie树的策略内存映射与缓存优化比如在搜索建议系统中可以采用分层Trie结构将热词放在内存中冷词放在磁盘上通过异步加载实现快速响应。

相关新闻

英特尔® Edison多语言编程环境数据共享:管道与ZeroMQ实战指南

英特尔® Edison多语言编程环境数据共享:管道与ZeroMQ实战指南

1. 项目概述:为什么我们需要在编程环境间分享数据? 作为一名在嵌入式领域摸爬滚打了十多年的开发者,我经历过无数次这样的场景:在PC上用Python写了个数据采集脚本,跑在Edison上,数据哗哗地来;然…

2026/7/29 10:47:34阅读更多 →
如何快速修复Visual C++运行库:新手友好的完整解决方案指南

如何快速修复Visual C++运行库:新手友好的完整解决方案指南

如何快速修复Visual C运行库:新手友好的完整解决方案指南 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 还在为"找不到MSVCR120.dll"或&q…

2026/7/29 10:47:34阅读更多 →
MLOps 上线治理:模型版本管理与 A/B 测试实践

MLOps 上线治理:模型版本管理与 A/B 测试实践

MLOps 上线治理:模型版本管理与 A/B 测试实践 一、模型上线的"开盲盒"风险 训练出一个新模型,指标比旧的好。兴冲冲推上线,结果线上用户投诉变多。回头一看,离线指标好,线上分布却偏了。 模型不同于普通代码…

2026/7/29 10:45:33阅读更多 →
FDA更新ESG NextGen AS2指南,易连EDI–EasyLink护航医药企业合规出海提交

FDA更新ESG NextGen AS2指南,易连EDI–EasyLink护航医药企业合规出海提交

2026年7月,美国FDA发布《Electronic Submission Gateway NextGen AS2 Guide for Industry Users》(v2.2),系统介绍了面向FDA的电子提交网关ESG NextGen。文件明确,AS2仍是行业向FDA报送监管资料的核心传输协议&#xf…

2026/7/29 18:19:48阅读更多 →
跨境多账号风控规避方案:基于QTphone的合规稳定运营技术解析

跨境多账号风控规避方案:基于QTphone的合规稳定运营技术解析

一、跨境账号风控核心技术诱因 海外平台风控系统采用多维度特征检测机制,除表层运营行为外,底层环境特征是核心判定依据。传统多账号运维模式存在三大技术漏洞:一是设备指纹复用,多账号共用设备参数,形成固定关联特征&…

2026/7/29 18:19:48阅读更多 →
如何快速上手kohya_ss:零基础打造专属AI画师的终极指南

如何快速上手kohya_ss:零基础打造专属AI画师的终极指南

如何快速上手kohya_ss:零基础打造专属AI画师的终极指南 【免费下载链接】kohya_ss 项目地址: https://gitcode.com/GitHub_Trending/ko/kohya_ss 你是否曾梦想拥有一个能理解你独特艺术风格的AI助手?现在,通过kohya_ss,这…

2026/7/29 18:19:48阅读更多 →
开源工具GBFR-Logs:实现《碧蓝幻想:Relink》精准数据监控的完整解决方案

开源工具GBFR-Logs:实现《碧蓝幻想:Relink》精准数据监控的完整解决方案

开源工具GBFR-Logs:实现《碧蓝幻想:Relink》精准数据监控的完整解决方案 【免费下载链接】gbfr-logs GBFR Logs lets you track damage statistics with a nice overlay DPS meter for Granblue Fantasy: Relink. 项目地址: https://gitcode.com/gh_mi…

2026/7/29 18:19:48阅读更多 →
Ryujinx模拟器:如何在PC上完美运行Switch游戏的完整指南

Ryujinx模拟器:如何在PC上完美运行Switch游戏的完整指南

Ryujinx模拟器:如何在PC上完美运行Switch游戏的完整指南 【免费下载链接】Ryujinx 用 C# 编写的实验性 Nintendo Switch 模拟器 项目地址: https://gitcode.com/GitHub_Trending/ry/Ryujinx 想在电脑上体验《塞尔达传说:旷野之息》、《超级马里奥…

2026/7/29 18:19:48阅读更多 →
5分钟免费实现专业级视频抠像:MatAnyone开源框架完整指南

5分钟免费实现专业级视频抠像:MatAnyone开源框架完整指南

5分钟免费实现专业级视频抠像:MatAnyone开源框架完整指南 【免费下载链接】MatAnyone [CVPR 2025] MatAnyone: Stable Video Matting with Consistent Memory Propagation 项目地址: https://gitcode.com/gh_mirrors/ma/MatAnyone 想要制作专业级视频背景替换…

2026/7/29 18:17:48阅读更多 →
覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

🔹 工具基础介绍 OpenClaw 是开源生态中一款实用性较强的本地智能工具,凭借本地离线运行、可视化图形操作和任务自动化三大核心特性,赢得了众多用户的青睐。与普通在线对话AI工具不同,它属于能够直接操控本机软硬件的智能数字员工…

2026/7/29 9:47:45阅读更多 →
伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

所谓液压伺服阀体的精密激光焊接,是用激光束对阀座壳体(通常为不锈钢或铝合金)进行密封焊接,使阀体在21-35MPa的高压液压油或压缩气体中长期运行而不发生介质泄漏。液压伺服阀是高端液压系统的"大脑"。从航空航天飞行控…

2026/7/29 7:00:19阅读更多 →
D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 你是否还在…

2026/7/29 7:58:51阅读更多 →
28. Agent 执行到一半想暂停?用 interrupt 给它设个“关卡“!

28. Agent 执行到一半想暂停?用 interrupt 给它设个“关卡“!

28. Agent 执行到一半想暂停?用 interrupt 给它设个“关卡“! 在构建复杂的 Agent 系统时,我们经常会遇到这样的场景:Agent 正在执行一个多步骤的任务,比如“下单购买商品”,但执行到一半时,我们…

2026/7/29 0:01:46阅读更多 →
自律同行,突破无界!NANK南卡正式官宣曾舜晞成为品牌代言人

自律同行,突破无界!NANK南卡正式官宣曾舜晞成为品牌代言人

近日,国际专注开放式技术研发的声学品牌Nank南卡,正式官宣实力艺人曾舜晞担任品牌代言人。消息一经发出便轰动全网。为什么耳机品牌不选择流量明星、老牌歌手?而且是选择曾舜晞?让我们一起来探索一下!比起短期的流量&a…

2026/7/29 0:01:46阅读更多 →
【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

一、本文介绍 🔥本文在RT-DETR多模态融合目标检测中引入RLAB残差线性注意力模块,可在不同模态特征交互阶段进行多次残差细化,使可见光、红外等特征在尺度、语义和空间位置上更好对齐;随后将细化特征与解码器输出拼接并生成Q、K、V,通过线性注意力自适应强化关键通道、目…

2026/7/29 0:01:46阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/28 20:22:24阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/29 4:31:51阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/29 14:26:42阅读更多 →