题目描述:
给定一个单词列表,我们将这个列表编码成一个索引字符串 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
每个单词都是小写字母 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/short-encoding-of-words
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
暴力解法:
class Solution {
public int minimumLengthEncoding(String[] words) {
if(words == null || words.length == 0){
return 0;
}
Arrays.sort(words,((o1, o2) -> o2.length() - o1.length()));
StringBuilder sb = new StringBuilder(words[0]+"#");
for (int i = 1; i < words.length; i++) {
int idx = sb.indexOf(words[i]);
if(idx >= 0 && sb.charAt(idx+words[i].length()) == '#'){
continue;
}
sb.append(words[i] + "#");
}
return sb.length();
}
}
字典树解法:
class TrieNode{
public int count;
public TrieNode[] nexts;
public TrieNode(){
count = 0;
nexts = new TrieNode[26];
}
public TrieNode get(char c){
if(nexts[c - 'a'] == null){
nexts[c - 'a'] = new TrieNode();
count++;
}
return nexts[c - 'a'];
}
}
class Solution {
public int minimumLengthEncoding(String[] words) {
if(words == null || words.length == 0){
return 0;
}
TrieNode root = new TrieNode();
Map<TrieNode,Integer> map = new HashMap<>();
for (int i = 0; i < words.length; i++) {
char[] ch = words[i].toCharArray();
TrieNode cur = root;
for (int j = ch.length - 1; j >= 0; j--) {
cur = cur.get(ch[j]);
}
map.put(cur,i);
}
int res = 0;
for (TrieNode node : map.keySet()) {
if(node.count == 0){
res += words[map.get(node)].length()+1;
}
}
return res;
}
}
思路概述:
先建树,一个count表示这个节点有几个分支,一个next[26]数组,代表26个字母的分支(未使用)。
定义一个get方法,先判断当前字母是否存在,如果不存在,就让当前分支指向一个新结点。
之后遍历words[ ]数组,并让每一个单词倒着插入。每一个单词插入完毕,都记录末尾结点和单词对应的坐标,存储到map中。
最后遍历map,count为0时(代表没有分支,为叶子结点),通过map找到对应的单词坐标,累加单词的长度,并加一(#的长度)。