我的LeetCode:https://leetcode-cn.com/u/ituring/
我的LeetCode刷题源码[GitHub]:https://github.com/izhoujie/Algorithmcii
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 <= words.length <= 2000
- 1 <= words[i].length <= 7
- 每个单词都是小写字母 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/short-encoding-of-words
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
- 分析完题目后发现,只要有相同后缀的都可以合并只统计较长的那个字符串长度并加1(#占一个长度)
- 问题在于如何去判断一堆字符串是否某几个有相同后缀,比较容易想到的是endWiths()和indexOf()两个方法,原理类似,但效率太低;
- endwiths()和indexOf()慢在每次每个字符都需要一次全扫描,如果能一次扫描并记录效率将成倍提升,所以更高效的是构造并记录索引,即Trie(单词查找树/字典树);
思路1-使用endwitchs()或indexOf()判断是否有相同后缀
步骤:
- 对所有单词按长度降序排序;
- 一次遍历,将单词追加到StringBuilder并每次额外追加一个#,追加的前提条件是StringBuilder中indexOf(当前单词+#)结果为-1;
- 返回StringBuilder的长度即为结果;
思路2-构造Trie,需要构造节点
步骤:
- 对所有单词按长度降序排序,定义节点Node类,持有一个26长度的Node数组,26个数对应a到z;
- 依次取每个单词,倒序遍历每个字符,并构造字典树,若需要新建节点说明是新单词,构造完统计其长度加1,若无需构造节点说明该单词是某个单词的后缀,不统计其长度;
- 累加统计的新单词长度即结果;
Trie树实际上是一颗每层都有26个子节点的多叉树,其实跟二叉树是一样的逻辑,只不过层节点变多了
算法源码示例
package leetcode;
import java.util.Arrays;
/**
* @author ZhouJie
* @date 2020年3月28日 下午9:53:38
* @Description: 820. 单词的压缩编码
*
*/
public class LeetCode_0820 {
}
class Solution_0820 {
/**
* @author: ZhouJie
* @date: 2020年3月28日 下午9:54:12
* @param: @param words
* @param: @return
* @return: int
* @Description: 1-按长度降序排序,然后拼接,使用indexof()
*
*/
public int minimumLengthEncoding_1(String[] words) {
// 按长度降序排序
Arrays.sort(words, (s1, s2) -> s2.length() - s1.length());
StringBuilder sb = new StringBuilder();
for (String s : words) {
if (sb.indexOf(s + "#") == -1) {
sb.append(s).append("#");
}
}
return sb.length();
}
/**
* @author ZhouJie
* @date 2020年3月29日 上午1:33:22
* @Description: 辅助索引节点
*
*/
class TrieNode {
TrieNode[] next = new TrieNode[26];
}
/**
* @author: ZhouJie
* @date: 2020年3月29日 上午1:33:24
* @param: @param words
* @param: @return
* @return: int
* @Description: 2-Trie,建立字典索引
*
*/
public int minimumLengthEncoding_2(String[] words) {
// 按长度降序排序
Arrays.sort(words, (s1, s2) -> s2.length() - s1.length());
int minLen = 0;
// 根索引
TrieNode root = new TrieNode();
for (String s : words) {
// 每次都从根开始搜索
TrieNode currNode = root;
// 当前单词是否需要单独新建索引
boolean f = false;
for (int i = s.length() - 1; i > -1; i--) {
// 细节, s.charAt(i) - 'a'即得到0-25对应到数组索引
int index = s.charAt(i) - 'a';
// 当前字符是否已建立索引,若未建立索引则新建索引并更新布尔值
if (currNode.next[index] == null) {
f = true;
currNode.next[index] = new TrieNode();
}
// 搜索下一个单词索引
currNode = currNode.next[index];
}
if (f) {
// 记录新建索引增加的长度
minLen += s.length() + 1;
}
}
return minLen;
}
}