从零学算法212

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

  • 这里我首先想到的是遍历所有 words,然后再遍历所有 board 尝试每个字符作为起点能否得到某个 word,但是超时了,这里可以转换思路,遍历所有 board,得到以每个字符开始,组成字符串的所有可能性,然后看是否在 words 中,是就加入结果列表 res
  •   // 方向数组int[][] dirs = new int[][]{{1,0},{-1,0},{0,1},{0,-1}};char[][] board;int m,n;// 存储 words 中的 wordSet<String> set = new HashSet<>();// 记录 board 中每个字符是否已使用boolean[][] visit = new boolean[12][12];// 结果列表List<String> res = new ArrayList<>();public List<String> findWords(char[][] _board, String[] words) {board = _board;m= board.length;n= board[0].length;for(String s:words)set.add(s);StringBuilder sb = new StringBuilder();// 尝试所有字符为起点得到可能的路径for(int i=0;i<m;i++){for(int j=0;j<n;j++){visit[i][j]=true;sb.append(board[i][j]);dfs(i,j,sb);visit[i][j] = false;sb.deleteCharAt(sb.length() - 1);}}return res;}void dfs(int i, int j, StringBuilder sb) {// 因为 word 长度至多为 10 所以再往后就不找了if(sb.length() > 10)return;// 当前路径在 set 中就得到一个结果,记得去除 set 中该路径if(set.contains(sb.toString())){res.add(sb.toString());set.remove(sb.toString());}for(int[] d : dirs){int x = i + d[0];int y = j + d[1];if(x < 0 || x >= m || y < 0 || y >= n)continue;if(visit[x][y])continue;visit[x][y] = true;sb.append(board[x][y]);dfs(x, y, sb);visit[x][y] = false;sb.deleteCharAt(sb.length() - 1);}}
    
  • 上述解法只在当前搜索路径达到 10 才进行剪枝,为了优化为每一步搜索都剪枝,我们可以使用前缀树(Trie),可以参考力扣 208 题的题解,我也趁此学习完记录了一下。该题解原文中也包含了前缀树的讲解。
  • 这里我们把 isEnd 直接替换为一个 String 类型的变量 s,记录该尾字符对应的字符串。我们创建一个前缀树,将 word 都存入其中,然后遍历 borad 每个字符作为起点,如果前缀树的根节点的子节点都不包含该字符,那就都不用 dfs 了直接下一位。
  • dfs 过程如果遇到了 s 不为 null 的情况,表示 board 存在路径对应 s(也就是 word),那就加入 set,因为 dfs 过程中可能不止一次找到该字符串,所以先用 set 记录,最后遍历添加到 res 即可。
  •   class Solution {class TrieNode {String s;TrieNode[] tns = new TrieNode[26];}void insert(String s) {TrieNode p = root;for (char c:s.toCharArray()) {int u = c - 'a';if (p.tns[u] == null) p.tns[u] = new TrieNode();p = p.tns[u];}p.s = s;}int[][] dirs = new int[][]{{1,0},{-1,0},{0,1},{0,-1}};char[][] board;int m,n;Set<String> set = new HashSet<>();boolean[][] visit = new boolean[12][12];List<String> res = new ArrayList<>();TrieNode root = new TrieNode();public List<String> findWords(char[][] _board, String[] words) {board = _board;m= board.length;n= board[0].length;for(String s:words)insert(s);for(int i=0;i<m;i++){for(int j=0;j<n;j++){int u = board[i][j] - 'a';// 前缀树中有字符串以当前字符开头才寻找路径if(root.tns[u] != null){visit[i][j]=true; dfs(i,j,root.tns[u]);visit[i][j] = false;}}}for(String s:set)res.add(s);return res;}void dfs(int i, int j, TrieNode node) {// 因为每一步都合法,所以只要能找到这一步就加入 setif(node.s != null)set.add(node.s);for(int[] d : dirs){int x = i + d[0];int y = j + d[1];if(x < 0 || x >= m || y < 0 || y >= n)continue;if(visit[x][y])continue;int u = board[x][y] - 'a';// 之前是写死了长度大于 10 则停止搜索// 而这里只要当前字符不在 word 的需求中就停止搜索// 比如 words 为 [abcd,accd,adcd],当前字符搜索到了前缀树第二层// 前缀树第二层包含了 [b,c,d],可如果当前字符是比如 e,那就不需要再找了// ae*** 无论如何都不会在 words 中if(node.tns[u] != null){visit[x][y] = true;dfs(x, y, node.tns[u]);visit[x][y] = false;}}}}
    

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

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

相关文章

@JsonProperty作用

jackson的maven依赖 <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.5.3</version> </dependency>JsonProperty 此注解用于属性上&#xff0c;作用是把该属…

二叉树|530.二叉搜索树的最小绝对差

力扣题目链接 class Solution { private: vector<int> vec; void traversal(TreeNode* root) {if (root NULL) return;traversal(root->left);vec.push_back(root->val); // 将二叉搜索树转换为有序数组traversal(root->right); } public:int getMinimumDiffe…

Mac vue3 使用可选链操作符 ?. 及空值合并操作符 ??编译报错

项目场景&#xff1a; uniapp使用vue3开发&#xff0c;引入uview-plus版本&#xff0c;无法编译通过&#xff08;无法使用可选链操作符 ?. &#xff09; 开发环境&#xff1a; 产品分类&#xff1a; uniapp/App P…

YoloV5改进策略:Block改进|ECA-Net:用于深度卷积神经网络的高效通道注意力|ECA+压缩膨胀Block实现涨点(独家原创)

摘要 本文使用ECA-Net注意力机制配合压缩膨胀的Block实现涨点。涨点方法是我自己独创的&#xff0c;改进方法简单易用&#xff0c;方便大家用于论文的改进。 论文&#xff1a;《ECA-Net&#xff1a;用于深度卷积神经网络的高效通道注意力》 arxiv.org/pdf/1910.03151.pdf 最…

LeetCode215. 数组中的第K个最大元素

题目描述&#xff1a; 给定整数数组 nums 和整数 k&#xff0c;请返回数组中第 k 个最大的元素。 请注意&#xff0c;你需要找的是数组排序后的第 k 个最大的元素&#xff0c;而不是第 k 个不同的元素。 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1: 输入…

后端系统开发之——功能完善

原文地址&#xff1a;https://blog.yiming1234.cn/?p830 下面是正文内容&#xff1a; 前言 通过SpringBoot开发用户模块的部分也就差不多要结束了&#xff0c;这一片文章就主要提一些在系统开发中需要注意到的细节部分和功能&#xff0c;也就是剩余的部分。 但是这个专栏只介…

echarts数据下钻如何配置

官方范例&#xff1a;https://echarts.apache.org/examples/zh/editor.html?cbar-multi-drilldown 看了一眼范例直接晕了&#xff0c;你这&#xff0c;一堆数据直接写死&#xff0c;这怎么用啊&#xff01; 一般来说&#xff0c;实现步骤是&#xff1a; 1&#xff09;后台&a…

安达发|电子产品制造企业APS生产排程软件

在电子脉动的世界中&#xff0c;时间是芯片上的电流&#xff0c;效率是电路板上的速度。在这个时代&#xff0c;每一微秒都蕴藏着无限可能&#xff0c;每一决策都关乎着企业的生死存亡。APS生产排程软件&#xff0c;是您的电子制造帝国中的智慧大脑&#xff0c;以卓越的创造力&…

Sqoop【实践 02】Sqoop1最新版 全库导入 + 数据过滤 + 字段类型支持 说明及举例代码(query参数及字段类型强制转换)

Sqoop1最新版举例 1.环境说明2.import-all-tables3.query4.字段类型支持 1.环境说明 还是之前的环境&#xff1a; # 不必要信息不再贴出 # JDK [roottcloud ~]# java -version java version "1.8.0_251" # MySQL [roottcloud ~]# mysql -V mysql Ver 14.14 Distrib…

Vue.js:构建高效且灵活的Web应用的利器

在前端开发领域&#xff0c;Vue.js已经迅速崛起并获得了广大开发者的青睐。作为一个轻量级的JavaScript框架&#xff0c;Vue.js不仅易于上手&#xff0c;而且功能强大&#xff0c;能够帮助开发者快速构建高效且灵活的Web应用。本文将带你深入了解Vue.js的核心概念、特性以及它在…

Reactor设计模式和Reactor模型

Reactor设计模式 翻译过来就是反应堆&#xff0c;所以Reactor设计模式本质是基于事件驱动。 角色 Handle&#xff08;事件&#xff09;EventHandler&#xff08;事件处理器&#xff09;ConcreteEventHandler&#xff08;具体事件处理器&#xff09;Synchronous Event Demult…

CTR之Session行为序列建模用户兴趣:DSIN

在前面的文章中&#xff0c;DIN模型 在用户行为序列建模中引入注意力机制来强调加权与target item相关的行为&#xff0c;以实现动态的兴趣表征&#xff1b;而DIEN模型 则在DIN的基础上加入时间性信息&#xff0c;使用注意力机制的GRU来挖掘用户兴趣的演变。 而今天的这篇文章…

jspssm_maven项目——KTV点歌系统

目录 背景 技术简介 系统简介 界面预览 背景 随着互联网的广泛渗透和进步&#xff0c;基于网络技术的KTV点歌系统迅速壮大&#xff0c;其发展始终围绕用户的实际需求展开。通过深入洞察用户的需求&#xff0c;开发出高度定制的管理平台&#xff0c;利用网络的便捷性对系统…

8.软件工程

整个章节偏向于记忆、背诵&#xff1b; 主要议题&#xff1a; 软件体系&#xff1a;3层&#xff1b; UML重点&#xff0c;重点记3要素中的关系、图&#xff1b; 1.软件体系结构 分层 优点&#xff1a;利于软件的重复利用&#xff1b; 缺点&#xff1a;以什么方式分层&#…

音频RK809

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、目的二、知识准备2.1Audio框架2.1.1 DAI2.1.2 CODEC2.1.3 machine三、原理图3.1 整体原理图3.2 喇叭部分3.3 麦克风部分四、设备树4.1 sound 部分4.2 codec 部分五、驱动讲

用友软件公司面试总结

一、自我介绍 二、质询 1. 对本公司的了解&#xff1f; 2. 身边同学对你的印象&#xff0c;认知、评价&#xff1f; 3. 你觉得身边人的评价符合吗&#xff1f; 4. 你觉得你的优点是什么&#xff1f; 5. 哪里人&#xff1f;会粤语吗&#xff1f; 6. 你对公司有多少了解&a…

使用Urllib库创建第一个爬虫程序

Urllib 是 Python 的标准库&#xff0c;它提供了一系列用于处理 URL 的函数和类&#xff0c;包括发送 HTTP 请求、处理 HTTP 响应、解析 URL 等功能。可以使用 urllib 来编写简单的网络爬虫。 request&#xff1a;它是最基本的HTTP请求模块&#xff0c;可以用来模拟发送请求。只…

【JavaScript 漫游】【044】Web Worker

文章简介 本篇文章为【JavaScript 漫游】专栏的第 044 篇文章&#xff0c;对浏览器模型的 Web Worker 相关知识点进行了总结。 概述 JavaScript 语言采用的是单线程模型&#xff0c;也就是说&#xff0c;所有任务只能在一个线程上完成&#xff0c;一次只能做一件事。前面的任…

设计模式|观察者模式(Observer Pattern)

文章目录 初识观察者模式优缺点示例代码&#xff08;使用 Java 实现&#xff09;有哪些知名的框架采用了观察者模式常见面试题 初识观察者模式 观察者模式&#xff08;Observer Pattern&#xff09;是一种软件设计模式&#xff0c;属于行为型模式。它定义了一种一对多的依赖关…

仿mudo库实现高并发服务器实现文章整合

相关文章实现与转载 (按实际项目流程发布) 时间轮设计-CSDN博客 正则表达式的使用-CSDN博客 bind函数的认识与基本使用-CSDN博客 timerfd的认识与基本使用-CSDN博客 Buffer缓冲区类实现(模块一)-CSDN博客 日志打印宏的编写-CSDN博客 Socket套接字类实现(模块二)-CSDN博…