单词的压缩编码。题意是给定一个单词列表,我们将这个列表编码成一个索引字符串 S 与一个索引列表 A。例如,如果这个列表是 ["time", "me", "bell"],我们就可以将其表示为 S = "time#bell#" 和 indexes = [0, 2, 5]。对于每一个索引,我们可以通过从字符串 S 中索引的位置开始读取字符串,直到 "#" 结束,来恢复我们之前的单词列表。请返回编码的长度。题目描述给的非常模糊,我拿例子解释一下,
Example:
Input: words =["time", "me", "bell"]
Output: 10 Explanation: S ="time#bell#" and indexes = [0, 2, 5
].Note:
1 <= words.length <= 2000
.1 <= words[i].length <= 7
.- Each word has only lowercase letters.
在input的数组里面有若干个单词,其中有一些词有可能是其他词的后缀,比如me就是time的后缀。题目只要求返回编码的长度10,而不需要返回对应的index所以会简单很多。这个题有两种做法,一种是用hashset,一种是用trie前缀树。我只能解释清楚第一种思路,前缀树的解法之后再补。题目中有提示到input里面单词的长度最长为7所以还勉强可以用hashset做。思路如下,
1. 用hashset存住input里面的每个单词
2. 遍历每个单词,看每个单词的每个substring后缀是否在hashset中存在,若存在就删除。比如还是time和me的例子吧,当扫描到time的后缀me的时候,发现me这整个单词在hashset里存在,所以可以直接将其删去,因为他一定不是编码的一部分。
3. 再次扫描hashset,因为此时去掉了所有可以当后缀的词,所以只需要累加所有hashset里面的元素的长度即可。
时间O(n^2) = O(number of words) * O(substring)
空间O(n) - hashset
Java实现
1 class Solution { 2 public int minimumLengthEncoding(String[] words) { 3 Setgood = new HashSet(Arrays.asList(words)); 4 for (String word : words) { 5 for (int k = 1; k < word.length(); k++) { 6 good.remove(word.substring(k)); 7 } 8 } 9 int res = 0; 10 for (String word : good) { 11 res += word.length() + 1; 12 } 13 return res; 14 } 15 }
JavaScript实现
1 /** 2 * @param {string[]} words 3 * @return {number} 4 */ 5 var minimumLengthEncoding = function(words) { 6 let hashSet = new Set(words); 7 for (let item of hashSet) { 8 for (let i = 1; i < item.length; i++) { 9 let target = item.slice(i); 10 hashSet.has(target) && hashSet.delete(target); 11 } 12 } 13 let res = 0; 14 hashSet.forEach(item => (res += item.length + 1)); 15 return res; 16 };