题目地址:单词的压缩编码
主要思路就是:判断新的字符串是否是之前已有字符串的后缀,如果是,则不予考虑,进入下一循环,最后返回每个字符串长度加一的总和。
其中用到了集合Set,它的特点是不能包含重复元素;
String类的substring()方法有两种用法:
public String substring(int beginIndex)
或
public String substring(int beginIndex, int endIndex)
-
beginIndex -- 起始索引(包括),索引从 0 开始。
-
endIndex -- 结束索引(不包括)。
class Solution {
public int minimumLengthEncoding(String[] words) {
//先将每个字符串存储到集合HashSet中
Set<String> chs = new HashSet<>(Arrays.asList(words));
//对于每个字符串,如果它的后缀作为单独字符串出现在集合中,则将那个后缀的字符串删除
for (String word : words) {
for (int i = 1; i < word.length(); i++) {
chs.remove(word.substring(i));
}
}
int res = 0;
//结果是每个字符串的长度加一的总和
for (String word : chs) {
res += word.length() + 1;
}
return res;
}
}
结果:
另外一种方法:字典树,看了好一会儿,主要思想是将每个字符串反序插入一颗树中,给每个字符串的单个单词赋予一个计数器,如果为0则代表是叶子节点,代表没有后缀的单词,最后计算所有叶子节点的单词长度加一的和。
class Solution {
public int minimumLengthEncoding(String[] words) {
TrieNode trieNode = new TrieNode();
Map<TrieNode,Integer> chs = new HashMap();
//遍历每个字符串
for (int i = 0; i < words.length; i++) {
String word = words[i];
TrieNode cur = trieNode;
/*如果当前字符串的该字符存在,则直接返回,
若不存在,则创建一个节点,且该字符的计数器加一,表明其已不是叶子节点*/
for (int j = word.length()-1; j >= 0 ; --j) {
cur = cur.get(word.charAt(j));
}
//将该单词存入集合,单词为键,下标为值
chs.put(cur,i);
}
int res = 0;
for (TrieNode node : chs.keySet()) {
//如果为叶子节点,找到该单词下标,求单词长度加一
if (node.count == 0)
res += words[chs.get(node)].length() + 1;
}
return res;
}
class TrieNode{
TrieNode[] child;
int count;
//构造函数,计数器初始为0
TrieNode(){
child = new TrieNode[26];
count = 0;
}
public TrieNode get(char c){
if (child[c-'a'] == null){
child[c-'a'] = new TrieNode();
count ++;
}
return child[c-'a'];
}
}
}
结果: