*leetcode 820. 单词的压缩编码-后缀树(待研究)

【题目】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
每个单词都是小写字母 。

【解题思路1】字典树、后缀树

在这里插入图片描述

class Solution {
    public int minimumLengthEncoding(String[] words) {
        int len = 0;
        Trie trie = new Trie();
        // 先对单词列表根据单词长度由长到短排序
        Arrays.sort(words, (s1, s2) -> s2.length() - s1.length());
        // 单词插入trie,返回该单词增加的编码长度
        for (String word: words) {
            len += trie.insert(word);
        }
        return len;
    }
}

// 定义tire
class Trie {
    
    TrieNode root;
    
    public Trie() {
        root = new TrieNode();
    }

    public int insert(String word) {
        TrieNode cur = root;
        boolean isNew = false;
        // 倒着插入单词
        for (int i = word.length() - 1; i >= 0; i--) {
            int c = word.charAt(i) - 'a';
            if (cur.children[c] == null) {
                isNew = true; // 是新单词
                cur.children[c] = new TrieNode();
            }
            cur = cur.children[c];
        }
        // 如果是新单词的话编码长度增加新单词的长度+1,否则不变。
        return isNew? word.length() + 1: 0;
    }
}

class TrieNode {
    char val;
    TrieNode[] children = new TrieNode[26];

    public TrieNode() {}
}

【解题思路2】反转-按字典排序

在这里插入图片描述

class Solution {
    public int minimumLengthEncoding(String[] words) {
        int N = words.length;
        // 反转每个单词
        String[] reversed_words = new String[N];
        for (int i = 0; i < N; i++) {
            String word = words[i];
            String rword = new StringBuilder(word).reverse().toString();
            reversed_words[i] = rword;
        }
        // 字典序排序    
        Arrays.sort(reversed_words);

        int res = 0;
        for (int i = 0; i < N; i++) {
            if (i+1 < N && reversed_words[i+1].startsWith(reversed_words[i])) {
                // 当前单词是下一个单词的前缀,丢弃
            } else {
                res += reversed_words[i].length() + 1; // 单词加上一个 '#' 的长度
            }
        }
        return res;
    }
}

在这里插入图片描述
还可以直接按照“逆序字典序排序” (待研究)

class Solution {
	public int minimumLengthEncoding(String[] words) {
	    int N = words.length;
	    
	    Comparator<String> cmp = (s1, s2) -> {
	        int N1 = s1.length();
	        int N2 = s2.length();
	        for (int i = 0; i < Math.min(N1, N2); i++) {
	            char c1 = s1.charAt(N1 - 1 - i);
	            char c2 = s2.charAt(N2 - 1 - i);
	            int c = Character.compare(c1, c2);
	            if (c != 0) {
	                return c;
	            }
	        }
	        return Integer.compare(N1, N2);
	    };
	    // 逆序字典序排序    
	    Arrays.sort(words, cmp);
	
	    int res = 0;
	    for (int i = 0; i < N; i++) {
	        if (i+1 < N && words[i+1].endsWith(words[i])) {
	            // 当前单词是下一个单词的后缀,丢弃
	        } else {
	            res += words[i].length() + 1; // 单词加上一个 '#' 的长度
	        }
	    }
	    return res;
	}
}
发布了134 篇原创文章 · 获赞 132 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/XunCiy/article/details/105168542