单词搜索
时间:2022-07-22
本文章向大家介绍单词搜索,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
问题描述:
给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。
输入:
words = ["oath","pea","eat","rain"] and board =
[
['o','a','a','n'],
['e','t','a','e'],
['i','h','k','r'],
['i','f','l','v']
]
输出: ["eat","oath"]
说明:
你可以假设所有输入都由小写字母 a-z 组成。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/word-search-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
大体思路:
看到题的第一反应是使用一Set存储所有words,以board中每个点开始使用dfs遍历出所有可能的单词,然后判断是否在set中。但是这种方法最大的缺点是不知道单词的长度,因此每遍历一步都需要判断当前单词是否在set中,此外由于不知道单词长度不得不把所有的位置都遍历到。
该问题可以使用前缀树结构替代hashSet,匹配到中间过程若到一个结点没匹配上,则可以直接回溯不需要再往下走了。如下图所示:不妨考虑此时刚好走过 ‘o’ ‘a’ 刚好来到下一个’a’,使用前缀树时此时可以直接回溯到上一步了,但是若时候hashSet时仍需要接着往下走。
实现代码如下:
class Solution {
int[][] directs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
public static class Node{
Node[] next;
boolean isEnd;
public Node(){
this.next = new Node[26];
this.isEnd = false;
}
}
Node root = null;
char[][] board;
boolean[][] access;
List<String> result;
public void createTri(String[] words){
this.root = new Node();
for(String word : words){
Node cur = root;
for(int i = 0; i < word.length(); i++){
char c = word.charAt(i);
if(cur.next[c - 'a'] == null){
cur.next[c - 'a'] = new Node();
}
cur = cur.next[c - 'a'];
if(i == word.length() - 1){
cur.isEnd = true;
}
}
}
}
public List<String> findWords(char[][] board, String[] words) {
createTri(words);
this.board = board;
this.access = new boolean[board.length][board[0].length];
this.result = new ArrayList<>();
StringBuilder temp = new StringBuilder();
for(int i = 0; i < board.length; i++){
for(int j = 0; j < board[0].length; j++){
dfs(i, j, root, temp);
}
}
return result;
}
public void dfs(int i, int j, Node cur, StringBuilder temp){
if(i < 0 || i >= board.length || j < 0 || j >= board[0].length ||
access[i][j] || cur.next[board[i][j] - 'a'] == null){
return;
}
cur = cur.next[board[i][j] - 'a'];
access[i][j] = true;
temp.append(board[i][j]);
if(cur.isEnd){
cur.isEnd = false; // 找到一个单词就删一个 防止重复
result.add(temp.toString());
}
for(int[] direct : directs){
dfs(i + direct[0], j + direct[1], cur, temp);
}
temp.deleteCharAt(temp.length() - 1);
access[i][j] = false;
}
}
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- SetConsoleTextAttribute函数用法
- C语言俄罗斯方块(旧版本)
- 线性表--顺序表--数组(三)
- 算法复杂度(二)
- 线性表--顺序表--单向链表(四)
- C语言俄罗斯方块(新版本完整代码)
- 线性表--顺序表--双向链表(六)
- C/C++什么时候使用二级指针,你知道吗?
- 萌新学习C++容易漏掉的知识点,看看你中招了没有(一)
- 萌新不看会后悔的C++string字符串常用知识点总结
- salesforce零基础学习(九十六)项目中的零碎知识点小总结(四)
- CodeForces - 260C
- 疯子的算法总结(九) 图论中的矩阵应用 Part 2 矩阵树 基尔霍夫矩阵定理 生成树计数 Matrix-Tree
- STL常用对象,不会搞得C++跟没学一样
- 桥接模式