leetcode
leetcode 801 ~ 850
单词子集

单词子集

难度:

标签:

题目描述

代码结果

运行时间: 120 ms, 内存: 19.4 MB


/*
 * 思路:
 * 1. 通过流计算 words2 中每个字母的最大频率。
 * 2. 使用流过滤和收集 words1 中满足条件的单词。
 */

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

public class SolutionStream {
    public List<String> wordSubsets(String[] words1, String[] words2) {
        int[] maxFreq = Arrays.stream(words2)
                .map(this::countFreq)
                .reduce(new int[26], (acc, bFreq) -> {
                    for (int i = 0; i < 26; i++) {
                        acc[i] = Math.max(acc[i], bFreq[i]);
                    }
                    return acc;
                });

        return Arrays.stream(words1)
                .filter(a -> isUniversal(countFreq(a), maxFreq))
                .collect(Collectors.toList());
    }

    private int[] countFreq(String s) {
        return s.chars().map(c -> c - 'a').collect(() -> new int[26], (arr, c) -> arr[c]++, (arr1, arr2) -> {
            for (int i = 0; i < 26; i++) {
                arr1[i] += arr2[i];
            }
        });
    }

    private boolean isUniversal(int[] aFreq, int[] maxFreq) {
        return IntStream.range(0, 26).allMatch(i -> aFreq[i] >= maxFreq[i]);
    }
}

解释

方法:

首先,将 words2 中的单词集合化,以去除重复的单词。接着,创建一个函数 jlzd 来计算 words2 中所有单词的最大字母频率需求。这个字典 d 将存储每个字符的最大出现次数,这是通过遍历 words2 的每个单词并更新每个字符的出现次数来实现的。然后,遍历 words1 中的每个单词,检查它是否包含字典 d 中所有字母的最小需求次数。如果某个单词满足所有条件,则认为它是通用单词,并将其添加到结果列表中。

时间复杂度:

O(B*L + A*M)

空间复杂度:

O(C + A)

代码细节讲解

🦆
为什么在处理`words2`时选择去除重复单词而不是直接统计所有单词的字符频率?
在处理`words2`时选择去除重复单词是为了简化问题和提高效率。重复的单词在计算最大字母频率需求时,不会改变结果,因为重复的单词提供的字母频率信息是相同的。这样,去除重复项后,可以减少后续操作的计算量,只需要分析更少的单词来确定每个字符的最大需求频率。
🦆
在函数`jlzd`中,为每个字符计算最大频率时,为什么选择在每次遇到字符时重新计算其出现次数而不是先统计每个单词的字符频率再进行比较?
这种选择可能是为了减少代码复杂度或者是考虑到实现的简便性。但是,这种方法效率较低,因为它会多次计算同一单词中字符的频率。更高效的方法是首先为每个单词建立一个字符频率字典,然后再比较更新全局的最大频率字典。这样可以减少重复的计数操作,提高算法的效率。
🦆
解决方案中有没有考虑到`words1`和`words2`为空的情况?如果没有,应该如何处理这些特殊情况?
题解中没有明确指出如何处理`words1`和`words2`为空的情况。通常,如果`words2`为空,则没有特定的字母频率需求,因此`words1`中的所有单词都应被认为是通用的;如果`words1`为空,则结果自然为空列表。在实现时,应该在函数开始时检查这些条件,适当地返回空列表或`words1`的全部内容。
🦆
在遍历`words1`中的单词时,如果一个单词不满足条件,立即使用`break`跳出循环。这种策略对算法性能有何影响?能否进一步优化?
使用`break`跳出循环的策略可以提高算法效率,因为它避免了在确定一个单词不符合条件后进行不必要的比较。这种策略可以尽早终止对当前单词的检查,节省时间。进一步优化可能包括使用更高效的数据结构来存储和比较频率,例如使用数组代替字典来存储字母频率,尤其是在字符集较小的情况下,如仅包含英文字母的场景。

相关问题