leetcode 解压缩_【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:nt方法(我的方法,超时)

class Solution {

public:

int minimumLengthEncoding(vector& words) {

int res = 0;

for (int i=0; i

for (int j=i+1; j

if (words[i] == "0") break;

if (words[j] == "0") continue;

if (words[i].back() != words[j].back()) continue; // 剪枝

if (words[i].size() > words[j].size()) {

if (words[j] == words[i].substr(words[i].size() - words[j].size()))

words[j] = "0";

}

else {

if (words[i] == words[j].substr(words[j].size() - words[i].size()))

words[i] = "0";

}

}

}

for (const auto& i : words) {

if (i != "0") {

res += i.size() + 1;

}

}

return res;

}

};

重点思路

时间复杂度O(N^2),用substr的方法切后缀,后缀长度为上一个字符串的长度。若和后缀相等则合并,并设为0,功能等同于erase。最后再统计words中所有不为0的字符串总长度。

解答2:字符串翻转+排序(占用内存少,方法泛用性不高)

class Solution {

public:

int minimumLengthEncoding(vector& words) {

int res = 0;

for (auto& i : words) {

reverse(i.begin(), i.end());

}

sort(words.begin(), words.end());

for (int i=0; i

if (words[i].size() > words[i+1].size() || words[i] != words[i+1].substr(0, words[i].size()))

res += words[i].size() + 1;

}

return res + words.back().size() + 1;

}

};

重点思路

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

解答3:前缀树、字典树、Trie方法(占用内存多,方法泛用性高)

class Trie {

private:

Trie* next[26] {nullptr};

public:

bool is_leaf = 1;

Trie() {}

Trie* insert(string s) {

Trie* root = this;

for (int i=s.size()-1; i>=0; i--) {

if (!root->next[s[i] - 'a']) {

root->next[s[i] - 'a'] = new Trie();

root->is_leaf = 0;

}

root = root->next[s[i] - 'a'];

}

return root;

}

};

class Solution {

public:

int minimumLengthEncoding(vector& words) {

int res = 0;

unordered_map ump; // 总个数为words中字符串个数

Trie* t = new Trie();

for (int i=0; i

ump[t->insert(words[i])] = i;

}

for (const auto& [n, i] : ump) {

if (n->is_leaf) {

res += words[i].size() + 1;

}

}

return res;

}

};

重点思路

由于该题需要大量运用字符串的前缀or后缀,很容易想到Trie方法。由于Trie为前缀树,所以放入Trie时使用倒序。本题使用所有叶子结点处所代表的字符串总和,故使用一个哈希表存放words中每个字符串是否含有叶子节点。本题的ump中,键中存放倒序后的每个字符串最后一个字母所在的节点,该节点含is_leaf成员变量来表示是否为叶子结点,键值存放该节点所在的字符串在words中对应的下标。

最后,遍历ump,将存在叶子结点的字符串全部长度相加,再加上对应的#即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值