【LeetCode-820】单词的压缩编码

问题

给定一个单词列表,我们将这个列表编码成一个索引字符串 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:字符串翻转+排序(时间复杂度较高,占用内存少)

class Solution {
public:
    int minimumLengthEncoding(vector<string>& words) {
        for (string& w : words) reverse(w.begin(), w.end()); // 字母逆序
        sort(words.begin(), words.end()); // 按字典序排序
        int res = 0;
        for (int i = 0; i < words.size() - 1; i++)
            if (check(words[i], words[i + 1])) res += words[i].size() + 1;
        return res + words.back().size() + 1;
    }
private:
    bool check(string& a, string& b) { // a为b前缀时返回0
        if (a.size() > b.size()) return 1;
        for (int i = 0; i < a.size(); i++)
            if (a[i] != b[i]) return 1;
        return 0;
    }
};

重点思路

首先翻转words中字符串,再使用sort排序。sort对字符串的默认排序方法是先比较字母大小,再比较长短,字母小的短的排在前面。翻转排序后,只需要比较相邻两个字符串即可。当前者不为后者前缀时,加上该字符的长度。

解答3:前缀树、字典树、Trie方法(占用内存多,时间效率高)

class Trie {
public:
    int isLeaf = 1; // 是否是叶节点
    int len = 0; // 单词长度
    Trie* insert(string& s) {
        Trie* root = this;
        for (int i = s.size() - 1; i >= 0; i--) {
            int index = s[i] - 'a';
            if (!root->next[index]) {
                root->next[index] = new Trie();
                root->isLeaf = 0;
            }
            root = root->next[index];
        }
        root->len = s.size();
        return root; // 返回当前指针,后续会使用对应的len和isLeaf
    }
private:
    Trie* next[26]{};
};

class Solution {
public:
    int minimumLengthEncoding(vector<string>& words) {
        int res = 0;
        unordered_set<Trie*> ust; // 用于去重
        Trie* t = new Trie();
        for (string& w : words)
            ust.insert(t->insert(w));
        for (auto& u : ust) // 结果包括所有位于叶子节点的单词长度
            if (u->isLeaf) res += u->len + 1;
        return res;
    }
};

重点思路

由于该题需要大量运用字符串的前缀or后缀,很容易想到Trie方法。由于Trie为前缀树,所以放入Trie时使用倒序。本题使用所有叶子结点处所代表的字符串总和。本题使用unordered_set对输入进行去重,每个返回的节点含is_leaf成员变量来表示是否为叶子结点,len成员变量表示该单词的长度。最后只需要将ustisLeaf = 1的成员长度想加即可。

posted @ 2021-02-07 18:12  tmpUser  阅读(70)  评论(0编辑  收藏  举报