leetcode第720题——词典中最长单词
leetcode题目:
给你一个字符串数组words,请你找出words中最长的一个单词且该单词要是由数组中其他单词添加一个字母而来的。若其中有多个可行的答案,则返回答案中字典序最小的单词。若无答案,则返回空字符串。
例子:输入:words = [“w”,“wo”,“wor”,“worl”, “world”]
输出:“world”
解释: 单词"world"可由"w", “wo”, “wor”, 和 "worl"逐步添加一个字母组成。
输入:words = [“a”, “banana”, “app”, “appl”, “ap”, “apply”, “apple”]
输出:“apple”
解释:“apply” 和 “apple” 都能由词典中的单词组成。但是 “apple” 的字典序小于 “apply”
解析:
常规解法:排序+HashSet
我们可以先对整个字符串数组进行排序(字符串之间的排序是从左往右按每个字母的字典序大小进行排列,直到一方没有字符为止)。
代码:
public String findLongestWord(String[] words){
Arrays.sort(words);
String result = "";
Set<String> set = new HashSet();
for(String s : words){
if(s.length() == 1 || set.contains(s.substring(0,s.length()-1)){
result = s.length() > result.length() ? s : result;
set.add(s);
}
}
return result;
}
排序+字典树(前缀树)解法
什么是字典树
字典树 (Trie),又称单词查找树、前缀树,是一种树形结构。
字典树的性质:
1.根节点不包含字符,除根节点外每一个节点都只包含一个字符;
2.从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串;
3.每个节点的所有子节点包含的字符都不相同。
如图:字典树储存 “a”、“apple”、“appeal”、“appear”、“bee”、“beef”、“cat” 这 7 个单词。
字典树的基础代码:
class TrieNode{
boolean exsit; //表示以该字母为最后一个字母的单词是否存在
//int count; //可以用来表示以该字符串为前缀的单词总数
TrieNode[] children;
TrieNode(){
exsit = false;
children = new TrieNode[26];
}
}
class Trie{
TrieNode root;
Trie(){
this.root = new TrieNode();
}
public void insert(String s){
TrieNode temp = root;
for(char c : s.toCharArray()){
if(temp.children[c-'a'] == null){
temp.children[c-'a'] = new TrieNode();
}
temp = temp.children[c-'a'];
}
//表示字典树中存在s字符串
temp.exsit = true;
}
public boolean inDictionary(String s){
TrieNode temp = root;
for(int i = 0 ; i < n ; i++){
char c = s.charAt(i);
temp = temp.children[c-'a'];
if(temp == null){
return false;
}
if(i == n-1 && temp.exsit == false){
return false;
}
}
return true;
}
}
字典树的应用场景
①用于字典: 字符串集合
②计算热词: 统计字符串在集合中出现的个数(寻找以某个字符串为前缀的单词总数)
③串的快速检索 给出 N 个单词组成的熟词表,以及一篇全用小写英文书写的文章,按最早出现的顺序写出所有不在熟词表中的生词。可以把熟词建成字典树,然后读入文章进行比较,这种方法效率是比较高的。(HashSet也可以)
④“串”排序 :给定N个互不相同的仅由一个单词构成的英文名,将他们按字典序从小到大输出,采用数组的方式创建字典树,这棵树的每个结点的所有儿子很显然地按照其字母大小排序。对这棵树进行先序遍历即可。(CompareTo方法也可以)
⑤最长公共前缀:对所有串建立字典树,对于两个串的最长公共前缀的长度即他们所在的结点的公共祖先个数,于是,问题就转化为当时公共祖先问题。
回归题目
学习完字典树的知识,我们再来回归题目。题目要求找出最长的单词且该单词是由数组中的字符串一步一步构建的。
代码如下:
public String longestWord(String[] words) {
Arrays.sort(words);
Trie trie = new Trie();
String result = "";
for(String s : words){
trie.insert(s);
if(trie.search(s.substring(0,s.length()-1) && s.length() > result.length()){
result = s;
}
}
return result;
}