题目描述
样例描述
思路
方法一:存储后缀 + 哈希去重
如果一个单词不是任何其他单词的后缀,那么它就是最短的编码。反之,是的话可以删除。
- 首先全部加入Set集合去重,对于每个单词,结合数据范围,依次在set里面删除它们所有的后缀。剩余的就是可编码的单词。加上1(#字符)的长度就是答案
方法二:排序 + 字典树 - 在方法一的基础上,可以把所有单词逆序挂在trie树上(方便查找后缀),在不断插入到树中,如果是新的单词,就需要编码为长度加一,否则直接用树上的不需要编码
- 注意要让长的单词先插入,如果短的先插入,并且是某长的后缀,将会被视为不同的。例如time,和me。 所以要先降序排序
代码
class Solution {
public int minimumLengthEncoding(String[] words) {
Set<String> set = new HashSet<>(Arrays.asList(words));
//枚举删除每个单词的所有后缀
for (String word: words) {
//由数据范围比较小,直接枚举删除
for (int k = 1; k < word.length(); k ++ ) {
set.remove(word.substring(k, word.length()));
}
}
//剩余的单词不是任何其他单词的后缀, 因此加上1 (#字符)求和就是答案
int ans = 0;
for (String s: set) {
ans += s.length() + 1;
}
return ans;
}
}
trie树
class Solution {
class TrieNode {
TrieNode tns[];
boolean isWord;
public TrieNode() {
tns = new TrieNode[26];
}
}
private TrieNode root;
public int insert(String word) {
TrieNode p = root;
//是否是新的,原trie树中不存在
boolean isNew = false;
for (int i = word.length() - 1; i >= 0; i -- ) {
int u = word.charAt(i) - 'a';
if (p.tns[u] == null) {
isNew = true;
p.tns[u] = new TrieNode();
}
p = p.tns[u];
}
//是新的话,就返回长度加一(#的字符),否则不用编码
return isNew ? word.length() + 1 : 0;
}
public int minimumLengthEncoding(String[] words) {
root = new TrieNode();
//降序排序
Arrays.sort(words, (a, b) ->{
return b.length() - a.length();
});
int ans = 0;
for (String s: words) {
ans += insert(s);
}
return ans;
}
}