来道算法题,压压惊。
给定一个单词列表,我们将这个列表编码成一个索引字符串 S 与一个索引列表 A。
例如,如果这个列表是 ["time", "me", "bell"],我们就可以将其表示为 S = "time#bell#" 和 indexes = [0, 2, 5]。
对于每一个索引,我们可以通过从字符串 S 中索引的位置开始读取字符串,直到 "#" 结束,来恢复我们之前的单词列表。
那么成功对给定单词列表进行编码的最小字符串长度是多少呢?
示例:输入: words = ["time", "me", "bell"]
输出: 10
说明: S = "time#bell#" , indexes = [0, 2, 5] 。
提示:1 <= words.length <= 2000 1 <= words[i].length <= 7 每个单词都是小写字母 。
对于每一个索引通过从字符串 S 中索引的位置开始读取字符串,直到 "#" 结束,来恢复之前的单词列表,其实就是求解所给出的单词列表中去除某些单词是其他单词后缀的情况,即保留所有不是其他单词后缀的单词。
解法一 将单词列表按照单词长度排序 从最长单词开始遍历 对于后续的每一个单词j 查看比它长度长的单词集合中是否有其可以作为后缀的,如果有,则说明单词j可以从集合中去除。最终将剩余单词集合长度相加即可。
// words = ["time", "me", "bell"] S = "time#bell#" , indexes = [0, 2, 5] 。 10
public int minimumLengthEncoding(String[] words) {
if(null==words || words.length==0) return 0;
if(words.length == 1) return words[0].length()+1;
Arrays.sort(words, Comparator.comparingInt(String::length));
int num = words[words.length-1].length()+1;
//System.out.println(Arrays.toString(words));
//StringBuilder sb = new StringBuilder();
//sb.append(words[words.length-1]);
//sb.append("#");
for(int i=words.length-2; i>=0; i--){
boolean flag = false;
for(int j=words.length-1; j>i; j--){
//System.out.println(words[j]+" "+words[i] + " " + words[j].contains(words[i]));
if(words[j].endsWith(words[i])){
flag = true;
break;
}
}
if(!flag){
//sb.append(words[i]);
//sb.append("#");
num += words[i].length()+1;
}
}
//System.out.println(sb.toString());
//return sb.length();
return num;
}
解法二 将单词列表放入集合set中,遍历单词列表,考虑每一个单词的可能后缀,将其从集合set中去除
代码如下:
public int minimumLengthEncoding2(String[] words) {
Set<String> set = new HashSet<>(Arrays.asList(words));
// 将所有可能的后缀从set中剔除
for(String word: words){
for(int k=1; k<word.length(); k++){
set.remove(word.substring(k));
}
}
int num = 0;
for(String s: set){
num += s.length()+1;
}
return num;
}
解法三 单词树
从每一个单词逆序放入单词树中,此时具有后缀包含的单词则隐藏长单词的单词路径中,统计单词树的长度即可
代码如下:
public int minimumLengthEncoding3(String[] words) {
TrieNode trie = new TrieNode();
Map<TrieNode, Integer> nodes = new HashMap<>();
for(int i=0; i<words.length; i++){
String word = words[i];
TrieNode cur = trie;
for(int j=word.length()-1; j>=0; j--){
cur = cur.get(word.charAt(j));
}
nodes.put(cur, i);
}
int ans = 0;
for(TrieNode node: nodes.keySet()){
if(node.count == 0){
ans += words[nodes.get(node)].length() + 1;
}
}
return ans;
}
class TrieNode {
TrieNode[] children;
int count;
TrieNode() {
children = new TrieNode[26];
count = 0;
}
public TrieNode get(char c){
int index = c - 'a';
if(null == children[index]){
children[index] = new TrieNode();
count++;
}
return children[index];
}
}
参考地址