哈希表题目:单词子集

题目

标题和出处

标题:单词子集

出处:916. 单词子集

难度

4 级

题目描述

要求

给你两个字符串数组 words1 \texttt{words1} words1 words2 \texttt{words2} words2

如果 b \texttt{b} b 中的每个字母都出现在 a \texttt{a} a 中,包括重复出现的字母,那么称字符串 b \texttt{b} b 是字符串 a \texttt{a} a子集

  • 例如, "wrr" \texttt{"wrr"} "wrr" "warrior" \texttt{"warrior"} "warrior" 的子集,但不是 "world" \texttt{"world"} "world" 的子集。

words1 \texttt{words1} words1 中的单词 a \texttt{a} a,如果对 words2 \texttt{words2} words2 中的每一个单词 b \texttt{b} b b \texttt{b} b 都是 a \texttt{a} a 的子集,那么我们称 a \texttt{a} a通用单词

以数组形式返回 words1 \texttt{words1} words1 中所有的通用单词。你可以按任意顺序返回答案。

示例

示例 1:

输入: words1   =   ["amazon","apple","facebook","google","leetcode"],   words2   =   ["e","o"] \texttt{words1 = ["amazon","apple","facebook","google","leetcode"], words2 = ["e","o"]} words1 = ["amazon","apple","facebook","google","leetcode"], words2 = ["e","o"]
输出: ["facebook","google","leetcode"] \texttt{["facebook","google","leetcode"]} ["facebook","google","leetcode"]

示例 2:

输入: words1   =   ["amazon","apple","facebook","google","leetcode"],   words2   =   ["l","e"] \texttt{words1 = ["amazon","apple","facebook","google","leetcode"], words2 = ["l","e"]} words1 = ["amazon","apple","facebook","google","leetcode"], words2 = ["l","e"]
输出: ["apple","google","leetcode"] \texttt{["apple","google","leetcode"]} ["apple","google","leetcode"]

数据范围

  • 1 ≤ words1.length,   words2.length ≤ 10 4 \texttt{1} \le \texttt{words1.length, words2.length} \le \texttt{10}^\texttt{4} 1words1.length, words2.length104
  • 1 ≤ words1[i].length,   words2[i].length ≤ 10 \texttt{1} \le \texttt{words1[i].length, words2[i].length} \le \texttt{10} 1words1[i].length, words2[i].length10
  • words1[i] \texttt{words1[i]} words1[i] words2[i] \texttt{words2[i]} words2[i] 仅由小写英语字母组成
  • words1 \texttt{words1} words1 中的所有字符串互不相同

解法

思路和算法

数组 words 1 \textit{words}_1 words1 中的单词 word \textit{word} word 是通用单词,等价于单词 word \textit{word} word 中的每个字母的出现次数都不小于数组 words 2 \textit{words}_2 words2 中的任意一个单词中的相同字母的出现次数。

最直观的做法是,首先统计出数组 words 2 \textit{words}_2 words2 中的每个单词中的每个字母的出现次数,然后遍历数组 words 1 \textit{words}_1 words1,对于每个单词 a a a,遍历数组 words 2 \textit{words}_2 words2 中的每个单词 b b b,判断单词 a a a 中的每个字母的出现次数是否都不小于单词 b b b 中的相同字母的出现次数。假设数组 words 1 \textit{words}_1 words1 words 2 \textit{words}_2 words2 的长度分别是 m m m n n n,则上述做法的时间复杂度至少为 O ( m n ) O(mn) O(mn),由于 m m m n n n 的最大值可达 1 0 4 10^4 104,因此上述做法的时间复杂度过高,需要优化。

由于通用单词中的每个字母的出现次数不小于数组 words 2 \textit{words}_2 words2 中的任意一个单词中的相同字母的出现次数,因此只需要记录每个字母在数组 words 2 \textit{words}_2 words2 中的单词中的最大出现次数即可,通用单词中的每个字母的出现次数不小于相同字母在数组 words 2 \textit{words}_2 words2 中的单词中的最大出现次数。

首先遍历数组 words 2 \textit{words}_2 words2 中的每个单词,并记录每个字母在数组 words 2 \textit{words}_2 words2 中的单词中的最大出现次数,然后遍历数组 words 1 \textit{words}_1 words1 中的每个单词 word \textit{word} word,根据单词 word \textit{word} word 中的每个字母的出现次数是否都不小于相同字母在数组 words 2 \textit{words}_2 words2 中的单词中的最大出现次数,判断单词 word \textit{word} word 是不是通用单词,将通用单词添加到结果列表。

实现方面,由于数组 words 1 \textit{words}_1 words1 words 2 \textit{words}_2 words2 中的每个单词只包含小写英语字母,因此可以使用长度为 26 26 26 的数组代替哈希表记录每个字母的出现次数。

代码

class Solution {
    public List<String> wordSubsets(String[] words1, String[] words2) {
        int[] unionCounts = new int[26];
        for (String word : words2) {
            int[] letterCounts = getLetterCounts(word);
            for (int i = 0; i < 26; i++) {
                unionCounts[i] = Math.max(unionCounts[i], letterCounts[i]);
            }
        }
        List<String> subsets = new ArrayList<String>();
        for (String word : words1) {
            boolean isUniversal = true;
            int[] letterCounts = getLetterCounts(word);
            for (int i = 0; i < 26; i++) {
                if (letterCounts[i] < unionCounts[i]) {
                    isUniversal = false;
                    break;
                }
            }
            if (isUniversal) {
                subsets.add(word);
            }
        }
        return subsets;
    }

    public int[] getLetterCounts(String word) {
        int[] letterCounts = new int[26];
        int length = word.length();
        for (int i = 0; i < length; i++) {
            char c = word.charAt(i);
            letterCounts[c - 'a']++;
        }
        return letterCounts;
    }
}

复杂度分析

  • 时间复杂度: O ( L 1 + L 2 + ∣ Σ ∣ × ( m + n ) ) O(L_1 + L_2 + |\Sigma| \times (m + n)) O(L1+L2+∣Σ∣×(m+n)),其中 m m m n n n 分别是数组 words 1 \textit{words}_1 words1 words 2 \textit{words}_2 words2 的长度, L 1 L_1 L1 L 2 L_2 L2 分别是数组 words 1 \textit{words}_1 words1 words 2 \textit{words}_2 words2 中的单词长度之和, Σ \Sigma Σ 是字符集,这道题中 Σ \Sigma Σ 是全部小写英语字母, ∣ Σ ∣ = 26 |\Sigma| = 26 ∣Σ∣=26
    首先需要遍历数组 words 2 \textit{words}_2 words2 中的全部单词并记录每个字母的最大出现次数,需要 O ( L 2 + ∣ Σ ∣ × n ) O(L_2 + |\Sigma| \times n) O(L2+∣Σ∣×n) 的时间。
    然后需要遍历数组 words 1 \textit{words}_1 words1 中的全部单词并判断每个单词是不是通用单词,需要 O ( L 1 + ∣ Σ ∣ × m ) O(L_1 + |\Sigma| \times m) O(L1+∣Σ∣×m) 的时间。
    因此总时间复杂度是 O ( L 1 + L 2 + ∣ Σ ∣ × ( m + n ) ) O(L_1 + L_2 + |\Sigma| \times (m + n)) O(L1+L2+∣Σ∣×(m+n))

  • 空间复杂度: O ( ∣ Σ ∣ ) O(|\Sigma|) O(∣Σ∣),其中 Σ \Sigma Σ 是字符集,这道题中 Σ \Sigma Σ 是全部小写英语字母, ∣ Σ ∣ = 26 |\Sigma| = 26 ∣Σ∣=26。空间复杂度主要取决于哈希表,需要使用哈希表记录每个字母在数组 words 2 \textit{words}_2 words2 中的单词中的最大出现次数,以及在遍历数组 words 1 \textit{words}_1 words1 时需要使用哈希表记录遍历到的单词中的每个字母的出现次数。注意返回值不计入空间复杂度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟大的车尔尼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值