🥈Medium

给定一个单词列表,我们将这个列表编码成一个索引字符串 S 与一个索引列表 A。

例如,如果这个列表是 ["time", "me", "bell"],我们就可以将其表示为 S = "time#bell#"indexes = [0, 2, 5]

对于每一个索引,我们可以通过从字符串 S 中索引的位置开始读取字符串,直到 “#” 结束,来恢复我们之前的单词列表。

那么成功对给定单词列表进行编码的最小字符串长度是多少呢?

示例

  1. 输入: words = ["time", "me", "bell"]
  2. 输出: 10
  3. 说明: S = "time#bell#" indexes = [0, 2, 5]

提示

  • 1 <= words.length <= 2000
  • 1 <= words[i].length <= 7
  • 每个单词都是小写字母

题解

十个月前做过的题目,今天再拿起来又不会了。这种接连失败的状态什么时候可以到头。真的好想努力之后能看到好的结果🙏🙏🙏。

方法一:存储后缀

如果单词X是Y的后缀,那编码Y的时候就同时将X编码了。如果单词X不在任何单词Y的后缀中出现,那X一定是编码字符串的一部分。
因此,目标就是保留所有不是其他单词后缀的单词,最后的结果就是这些单词长度加一的总和(每个单词后需加#)
820_1.gif

Python

  1. class Solution:
  2. def minimumLengthEncoding(self, words: List[str]) -> int:
  3. good = set(words)
  4. for word in words:
  5. for k in range(1, len(word)):
  6. good.discard(word[k:])
  7. return sum(len(word) + 1 for word in good)

JavaScript

  1. /**
  2. * @param {string[]} words
  3. * @return {number}
  4. */
  5. var minimumLengthEncoding = function(words) {
  6. const wordSet = new Set(words)
  7. for (let i in words){
  8. for(let j = 1;j<words[i].length;j++){
  9. wordSet.delete(words[i].slice(j))
  10. }
  11. }
  12. let sum=0
  13. wordSet.forEach(item => sum+=item.length+1)
  14. return sum
  15. };

复杂度分析

  • 时间复杂度:🥈820. 单词的压缩编码@ - 图2,其中是word[i]的长度。每一个单词有🥈820. 单词的压缩编码@ - 图3个后缀,对于每个后缀,查询其是否在集合中需要🥈820. 单词的压缩编码@ - 图4的哈希值计算
  • 空间复杂度:🥈820. 单词的压缩编码@ - 图5,存储单词的空间开销


方法二:字典树

目的就是保留所有不是其他单词后缀的单词。可以去找到是否不同的单词具有相同的后缀,我们可以将其反序之后插入字典树中。这样emit和em才有前缀关系,直接用time和me是没有前缀关系的。例如,我们有 “time” 和 “me”,可以将 “emit” 和 “em” 插入字典树中。