leetcode 题目820 单词的压缩编码

2020/3/28  打卡

题目

给定一个单词列表,我们将这个列表编码成一个索引字符串 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] 。

思路

这里首先理解题意, 是针对indexes中指定的索引位置读起,一直读到#位置,针对于示例,其读取过程是:
           (1)从0索引的t开始读, 一直读到#位置,第一次读到的单词是 time
           (2)从2索引的 m开始,一直读到#位置,读到的单词是 me
           (3)从5索引的 b开始,一直读到#位置,读到的单词是 bell
        明白了吧,这里使用尽量短的S  来实现上面的索引压缩查找效果。
解法上撕下字典树(trie树)吧 
  用递归的方式 构造字典树,对于每个单词从从后往前处理。
  最后答案是每个叶子节点的层数的和(编码字符串中的单词长度) + 叶子节点数量(#数量)

代码

class Solution:
    def minimumLengthEncoding(self, words):
        class Node:
            def __init__(self, l):
                # 层数
                self.l = l
                # children是对应的孩子。 对应树中的分叉,分成多个孩子
                self.children = {}

        root = Node(0)


        ##########################  递归构建前缀树  ###################
        # 递归构造字典树   递归构建的过程,不断加入新词w   (注意这里是将单词的最后一个字母,从后往前构建的树,)
        def build(t, w):
            if not w:
                return

            # 把最后一个字母作为树的分叉孩子,  声明层数,并创建了一个树结点
            if w[-1] not in t.children:
                t.children[w[-1]] = Node(t.l + 1)

            # 构建树时,一个一个字母的放置构建,
            build(t.children[w[-1]], w[:-1])
        # 对于 单词数组,逐步构建
        for w in words:
            build(root, w)

        ##########################  针对构建好的树,算出拼成所有单词的最短长度 ###################
        #  对应的计算方式可以看题解中的 图,就是那个5+4+3+5=17的计算过程,比较简单。  https://leetcode-cn.com/problems/short-encoding-of-words/solution/dan-ci-de-ya-suo-bian-ma-by-leetcode-solution/
        # 相当于全局变量,以便在递归中累加
        ans = [0]
        # 计算答案
        def vis(t):
            # 是叶子节点                    只在叶子节点处,统计长度的累加,利用高度做累加。
            if len(t.children) == 0:
                if t.l > 0:
                    # 累加
                    ans[0] += t.l + 1
            # 非叶子节点,就直接继续往下走
            for c in t.children.values():
                vis(c)
        vis(root)
        return ans[0]

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值