题目:
Given a list of strings
words
representing an English Dictionary, find the longest word inwords
that can be built one character at a time by other words inwords
. If there is more than one possible answer, return the longest word with the smallest lexicographical order.
If there is no answer, return the empty string.
Example 1:Input: words = ["w","wo","wor","worl", "world"] Output: "world" Explanation: The word "world" can be built one character at a time by "w", "wo", "wor", and "worl".
Example 2:
Input: words = ["a", "banana", "app", "appl", "ap", "apply", "apple"] Output: "apple" Explanation: Both"apply" and "apple" can be built from other words in the dictionary. However, "apple" is lexicographically smaller than "apply".
Note:
All the strings in the input will only contain lowercase letters.
The length ofwords
will be in the range[1, 1000]
.
The length ofwords[i]
will be in the range[1, 30]
.
解释:
用set()
,如果当前word
除了最后一个字母以外的子字符串在set中,则把当前word加入到set中,加入完成后把当前的word和此前最长的word做比较,因为要返回字典序最小的,所以刚开始要对words
排序。
觉得解决这道题的经典解法是前缀树解法。
python代码:
class Solution(object):
def longestWord(self, words):
"""
:type words: List[str]
:rtype: str
"""
if not words:
return ""
longestword=''
wordset=set([''])
words.sort()
for word in words:
if word[:-1] in wordset:
wordset.add(word)
if len(longestword)<len(word):
longestword=word
return longestword
c++代码:
#include<set>
using namespace std;
class Solution {
public:
string longestWord(vector<string>& words) {
set<string> _set;
_set.insert("");
sort(words.begin(),words.end());
string longestword="";
for(auto word:words)
{
if (_set.count(word.substr(0,word.size()-1)))
{
_set.insert(word);
if (word.size()>longestword.size())
longestword=word;
}
}
return longestword;
}
};
前缀树解法,速度略慢:
python代码:
#觉得这道题目也是字典树的经典题目
#需要先改一下原本的search函数。
from collections import defaultdict
class TrieNode(object):
def __init__(self):
self.children=defaultdict(TrieNode)
self.isWord=False;
class Solution(object):
def longestWord(self, words):
"""
:type words: List[str]
:rtype: str
"""
def insert(root,word):
current=root
for letter in word:
current=current.children[letter]
current.isWord=True
def search(root,word):
current=root
for letter in word:
current=current.children.get(letter)
if not current or not current.isWord :
return False
return True
root=TrieNode()
for word in words:
insert(root,word)
result=[]
maxLen=0
for word in words:
if search(root,word):
lenWord=len(word)
if lenWord>maxLen:
result=[word]
maxLen=lenWord
elif lenWord==maxLen:
result.append(word)
return sorted(result)[0] if result else ""
c++代码(比set的解法略快):
#include <map>
using namespace std;
struct TrieNode{
bool isWord;
map<char,TrieNode*> children;
TrieNode():isWord(false){}
};
class Solution {
public:
string longestWord(vector<string>& words) {
TrieNode* root=new TrieNode();
vector<string> result;
for (auto word:words)
insert(root,word);
int maxLen=0;
for (auto word:words)
{
int n =word.size();
if (search(root,word))
{
if (n>maxLen)
{
maxLen=n;
result={word};
}
else if(n==maxLen)
result.push_back(word);
}
}
if (result.size()==0)
return "";
sort(result.begin(),result.end());
return result[0];
}
void insert(TrieNode* root ,string word)
{
TrieNode* current=root;
for(auto letter:word)
{
if(!current->children.count(letter))
current->children[letter]=new TrieNode();
current=current->children[letter];
}
current->isWord=true;
}
bool search(TrieNode* root,string word)
{
TrieNode* current=root;
for(auto letter:word)
{
if(!current->children.count(letter) )
return false;
current=current->children[letter];
if (!current->isWord)
return false;
}
return true;
}
};
总结:
发现各种利用前缀树的题目,虽然都是在用前缀树,但是具体的写法还是不同的,主要是改TrieNode()
的定义,insert()
函数和serach()
函数。
前缀树写熟练了就和二叉树差不多了。