Google 面试题分析 | 字典里面的最长单词
Posted 汤高
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Google 面试题分析 | 字典里面的最长单词相关的知识,希望对你有一定的参考价值。
Google 面试题分析 | 字典里面的最长单词
描述
给定一个字符串列表words,找到words最长的word,使得这个word可用words中的其他word一次一个字符地构建。如果有多个可选答案,则返回最长的且具有最小字典序的word。
样例
Ⅰ. Input: words =["w","wo","wor","worl","world"]
Output: "world"
Explanation: “world”可通过”w”, “wo”, “wor”, “worl”一次一个字符进行构建。
Ⅱ . Input: words =["a", "banana", "app", "appl","ap", "apply", "apple"]
Output:"apple"
Explanation: “apply”和”apple”都可以由其他字符构建。但”apple”的字典序要小于”apply”。
注意:
所有的输入字符只包含小写字符。
words的长度在[1, 1000]范围内。
words[i]的长度在[1, 30]范围内。
解题思路
方法一:直接采用暴力搜索。
对于每一个word,检查是否其前缀都在words中。可以用words构建set。初始化ans=””,words,对每个元素,在set中寻找是否有其所有前缀。如果当前word合题,且长度大于ans,或长度等于ans但字典序小于ans,则修改ans为当前word。也可以先对words排序,按照长度从小到大,长度相同按照字典顺序。这样只要word合题就修改ans。
时间复杂度:O(sum(w_i^2)),w_i表示words[i]的长度。对于每一个word,通过哈希表检查是否所有的前缀都在set当中需要O(w_i^2)。
空间复杂度:O(sum(w_i))用于创建set。
方法二:因为涉及到了字符串的前缀,所以使用Trie结构(一种字符串前缀树)。
trie树的介绍参见 Trie树介绍把每个word放入Trie中,对Trie进行DFS,只搜索终结节点。每个找到的节点中(除了根)从根到该节点路径代表该节点的word。之后同方法一:如果当前word合题,且长度大于ans,或长度等于ans但字典序小于ans,则修改ans为当前word。
时间复杂度:O(sum(w_i)),w_i是words[i]的长度。这是构建和便利Trie的复杂度。如果使用BFS而不是DFS,并且把每个节点的子节点进行排序,那么我们就不需要再去检查当前的word时候比ans要好,后访问的节点一定要好于先访问的节点,但复杂度不变。
空间复杂度:O(sum(w_i))用于构建Trie。
代码实现
package trie;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
public class Solution
class Trie
//待构建的字符串列表
private String words[];
private Node root;
public Trie(String[] words)
this.root=new Node();
this.words=words;
public Node builtTrie()
int index=0;
for (int i=0;i<words.length;i++)
insert(words[i],++index);
return root;
/**
*@param index表示在words数组中的索引,方便在trie节点中快速获取该单词
*/
public void insert(String word,int index)
if(word==""||word==null)
return;
Node cur=root;
char [] chars=word.toCharArray();
for(int i=0;i<chars.length;i++)
//如果不存在该值,则创建新节点
char val=chars[i];
if(!cur.getChildrens().containsKey(val))
Node newNode=new Node();
newNode.setVal(val);
cur.getChildrens().put(val, newNode);
//如果已经存在则pass
cur=cur.getChildrens().get(val);
cur.setEnd(index);
public String DFS()
String result="";
Stack<Node> stack=new Stack<Node>();
stack.push(root);
while(!stack.isEmpty())
Node node=stack.pop();
if(node.getEnd()>0||node==root)
if(node!=root)
String word= this.words[node.getEnd()-1];
if(word.length()>result.length()||
word.length()==result.length()&&result.compareTo(word)>0)//最长的且具有最小字典序的word
result=word;
for(Node n:node.getChildrens().values())//拿到子节点
stack.push(n);
return result;
class Node
// 节点字符值
private char val;
// 节点的子节点,即以根节点到该节点的值组成的字符串为前缀的字符串构建的节点
private Map<Character, Node> childrens = new HashMap<Character, Node>();
// 是否为结束节点,即一个字符串是否到达末尾节点 当end>0时表示结束节点 该节点存储单词在words列表中的位置
private int end = 0;
public char getVal()
return val;
public void setVal(char val)
this.val = val;
public Map<Character, Node> getChildrens()
return childrens;
public void setChildrens(Map<Character, Node> childrens)
this.childrens = childrens;
public int getEnd()
return end;
public void setEnd(int end)
this.end = end;
public static void main(String[] args)
String[] words=new String[]"a", "banana", "app", "appl", "ap", "apply", "apple";
//String[] words=new String[]"w","wo","wor","worl", "world";
Solution s=new Solution();
Trie t=s.new Trie(words);
t.builtTrie();
System.out.println( t.DFS());
转载请指明出处http://blog.csdn.net/tanggao1314/article/details/79004972
参考 https://mp.weixin.qq.com/s/WTXUt9C0YEl6171HbVWXWQ
以上是关于Google 面试题分析 | 字典里面的最长单词的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode 524. 通过删除字母匹配到字典里最长单词(动态规划) / 695. 岛屿的最大面积 / 54. 螺旋矩阵(背)
LeetCode 720 词典中最长的单词[排序 set 字典树] HERODING的LeetCode之路
LeetCode 524. Longest Word in Dictionary through Deleting (通过删除字母匹配到字典里最长单词)