LeetCode 820. 单词的压缩编码

我的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()判断是否有相同后缀

步骤:

  1. 对所有单词按长度降序排序;
  2. 一次遍历,将单词追加到StringBuilder并每次额外追加一个#,追加的前提条件是StringBuilder中indexOf(当前单词+#)结果为-1;
  3. 返回StringBuilder的长度即为结果;

思路2-构造Trie,需要构造节点

步骤:

  1. 对所有单词按长度降序排序,定义节点Node类,持有一个26长度的Node数组,26个数对应a到z;
  2. 依次取每个单词,倒序遍历每个字符,并构造字典树,若需要新建节点说明是新单词,构造完统计其长度加1,若无需构造节点说明该单词是某个单词的后缀,不统计其长度;
  3. 累加统计的新单词长度即结果;

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;
	}
}

你可能感兴趣的:(LeetCode 820. 单词的压缩编码)