题目:
单词数组 words 的 有效编码 由任意助记字符串 s 和下标数组 indices 组成,且满足:
words.length == indices.length- 助记字符串
s以'#'字符结尾 - 对于每个下标
indices[i],s的一个从indices[i]开始、到下一个'#'字符结束(但不包括'#')的 子字符串 恰好与words[i]相等
给你一个单词数组 words ,返回成功对 words 进行编码的最小助记字符串 s 的长度 。
算法:
方法一:存储后缀
读懂题意很重要,1.indices数组是可以任意指定的;2.indices[i]到#之前的子字符串与word[i]相等,a是b的后缀相等则可以编码到一起。那么我们可以尽可能把短的字符串尝试匹配长的字符串的后缀。如果能匹配上,就把短的字符串删掉。
func minimumLengthEncoding(words []string) int {
set := make(map[string]struct{})
for i := 0; i < len(words); i++ {
set[words[i]] = struct{}{}
}
for i := 0; i < len(words); i++ {
for j := 1; j < len(words[i]); j++ {
if _, ok := set[words[i][j:]]; ok {
delete(set, words[i][j:])
}
}
}
ans := 0
for word := range set {
ans = ans + len(word) + 1
}
return ans
}
方法二:tier字典树
将words的每个字符串反序插入字典树,看插入了多少的字符串
func minimumLengthEncoding(words []string) int {
tier := NewTier()
nodeWordIndexMap := make(map[*Tier]int)
// 遍历words,对word逆序构建tier树
for i := range words {
cur := tier
for j := len(words[i]) - 1; j >= 0 ;j -- {
cur = cur.Get(int(words[i][j] - 'a'))
}
// 这里很巧妙,假设生成e-m-i-t-leaf,此时cur=leaf,leaf.Count=0 ,如果继续生成了e-m,则leaf节点=i,count=1,不是叶子节点,所以以此来用 if node.Count == 0判断是否叶子节点。
nodeWordIndexMap[cur] = i
}
// 遍历tier数组,如果是叶子节点,则ans = ans + len(word) + 1
ans := 0
for node, index := range nodeWordIndexMap {
if node.Count == 0 {
ans = ans + len(words[index]) + 1
}
}
return ans
}
// tier树
type Tier struct{
Nodes []*Tier
Count int
}
func NewTier() *Tier {
return &Tier{make([]*Tier, 26), 0}
}
func (t *Tier) Get(index int) *Tier {
if t.Nodes[index] == nil {
t.Nodes[index] = NewTier()
t.Count ++
}
return t.Nodes[index]
}