leetcode
leetcode 2951 ~ 3000
单词的压缩编码

单词的压缩编码

难度:

标签:

题目描述

English description is not available for the problem. Please switch to Chinese.

代码结果

运行时间: 46 ms, 内存: 16.4 MB


/*
 * 思路:
 * 1. 对单词数组进行排序,按照单词的逆序排列
 * 2. 使用一个Set存储所有单词的后缀
 * 3. 遍历排序后的单词数组,检查每个单词是否在Set中,如果不在则将该单词的所有后缀加入Set,并增加编码长度
 * 4. 最后得到的编码长度即为最小助记字符串的长度
 */
import java.util.*;
import java.util.stream.Collectors;

public class MinimumLengthEncoding {
    public int minimumLengthEncoding(String[] words) {
        // 对单词数组进行排序,按照单词的逆序排列
        List<String> sortedWords = Arrays.stream(words)
                                         .sorted((a, b) -> new StringBuilder(b).reverse().toString().compareTo(new StringBuilder(a).reverse().toString()))
                                         .collect(Collectors.toList());
        Set<String> set = new HashSet<>();
        final int[] result = {0};
        // 遍历排序后的单词数组
        sortedWords.forEach(word -> {
            if (!set.contains(word)) {
                // 如果Set中不包含当前单词,则将该单词的所有后缀加入Set
                for (int i = 0; i < word.length(); i++) {
                    set.add(word.substring(i));
                }
                // 增加编码长度
                result[0] += word.length() + 1;
            }
        });
        return result[0];
    }

    public static void main(String[] args) {
        MinimumLengthEncoding solution = new MinimumLengthEncoding();
        String[] words = {"time", "me", "bell"};
        System.out.println(solution.minimumLengthEncoding(words)); // 输出 10
    }
}

解释

方法:

这个题解的核心思路是利用排序和字符串后缀的比较来确定哪些单词是其他单词的后缀。首先,将每个单词逆序,然后对这些逆序后的单词进行排序。排序后,如果某个单词是另一个单词的前缀(由于单词已经逆序,实际上检查的是后缀),则这个单词可以被完全包含在另一个单词的编码中。遍历排序后的单词列表,如果一个单词不是下一个单词的前缀,则它需要单独计入最终的编码字符串中,计算长度时要加上一个字符的空间来放置分隔符'#'。

时间复杂度:

O(n log n)

空间复杂度:

O(nk)

代码细节讲解

🦆
为什么选择将单词逆序后再进行排序,而不是直接排序原始单词?
逆序单词后排序的主要目的是为了方便检查一个单词是否为另一个单词的后缀。如果直接对原始单词排序,那么排序的结果是基于单词的前缀顺序,这并不利于我们检查后缀关系。逆序后排序使得具有共同后缀的单词会聚集在一起,这样只需要检查当前单词是否为下一个单词的前缀(因为已经逆序,所以前缀检查实际上是后缀检查),从而有效地实现压缩编码。
🦆
在排序逆序单词的过程中,如何处理长度不同但内容相似的单词,例如单词 'a' 和 'ba'?
当逆序单词后,'a' 会变为 'a',而 'ba' 会变为 'ab'。在对这些逆序后的单词排序时,'a' 会排在 'ab' 前面。在遍历排序后的单词列表进行压缩编码检查时,我们会检查一个单词是否是下一个单词的前缀。在这个例子中,'a' 不是 'ab' 的前缀,所以 'a' 需要被单独计入最终的编码长度。这种处理方式确保了即使单词长度不同,只要它们不是后缀关系,都会被正确处理。
🦆
题解中提到如果一个单词是下一个单词的前缀则可以被包含,这种方法是否考虑了多个连续单词可能相互包含的情况?
是的,这种方法已经考虑了多个连续单词可能相互包含的情况。通过对逆序后的单词进行排序,任何可以被包含的单词关系都会通过前缀关系表现出来,并且会按照从短到长的顺序排列。在遍历这个排序后的列表时,我们会连续检查每个单词是否是下一个单词的前缀。如果是,则当前单词可以被包含在下一个单词中。如果不是,则当前单词需要单独计入编码长度中。这种方式确保了即使是多个单词相互包含,每个单词都会被正确地处理。

相关问题