zoukankan      html  css  js  c++  java
  • 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;
    	}
    }
    
  • 相关阅读:
    Java入门——day42
    第六周进度报告
    Java入门——day41
    Java入门——day40
    Java入门——day39
    Java入门——day38
    Java入门——day37
    Java入门——day36
    Java入门——day35
    第五周进度报告
  • 原文地址:https://www.cnblogs.com/izhoujie/p/12595022.html
Copyright © 2011-2022 走看看