Post

916. Word Subsets

916. Word Subsets

[Problem]

Medium

Array String Hash Table


Intuition

  • The question is pretty straightforward, it asks us to verify which words in array words1 are universal or not.

  • Lets call the arrays words1 -> A and words2 -> B

  • Now observe this example:
    1
    2
    
      A = ["aabc", "ef", "xaaaabcd", "abccdefaa"];
      B = ["aaac", "aab", "ccbd"];
    
  • What characters do we need in any string in A to be universal?

  • Let us observe the frequencies of all characters in strings in B
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
      aaac => {a: 3, c: 1}
      aab =>  {a: 2, b: 1}
      ccbd => {c: 2, b: 1, d:1}
    
      For any string to be universal, it has to have
          3 `a`   => max frequency of `a` among all strings in `B`
          2 `c`   => max frequency of `c` among all strings in `B`
          1 `b`   => max frequency of `b` among all strings in `B`
          1 `d`   => max frequency of `d` among all strings in `B`
        
      ----------------------------------------------
      Observe that strings in `A` that follow this requirement are: "xaaaabcd" and "abccdefaa"
      Hence, these two are universal strings!
    
  • Hence we need to update the maximum frequencies of characters among all strings in B

  • Now, we check if the required number of each character is present in any string in A. If so, it is considered universal.

Approach

  • For each word in words2, calculate max frequency of each character among all strings.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
          // Array to store the maximum frequency of each character across all strings in `words2`
          int[] maxFreq = new int[26];
    
          // calculate maxFreq of each character across all strings in `words2`
          for (String word : words2) {
              int[] currentWordFreq = new int[26];
    
              for (char ch : word.toCharArray()) {
                  currentWordFreq[ch - 'a']++;
    
                  // Update maxFreq for each character
                  maxFreq[ch - 'a'] = Math.max(maxFreq[ch - 'a'], currentWordFreq[ch - 'a']);
              }
          }
    
  • Now traverse through each word in words1, make its character frequency array, and check if the string is universal

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
      for (String word : words1) {
          // frequency array for the current word in words1
          int[] wordFreq = new int[26];
    
          for (char ch : word.toCharArray()) {
              wordFreq[ch - 'a']++;
          }
          // check if the word is universal
          if (isUniversal(wordFreq, maxFreq)) {
              universalWords.add(word);
          }
      }
    
  • isUniversal method: When the maxFreq[i] > wordFreq[i], means there are NOT enough no. of current character in this word to become universal.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
      // method to check if a word is universal
      private boolean isUniversal(int[] wordFreq, int[] maxFreq) {    
          // verify if `wordFreq` satisfies the `maxFreq` for all characters
          for (int i = 0; i < 26; i++) {
              // `maxFreq[i]` is minimum frequency we need for `wordFreq[i]` 
              if (maxFreq[i] > wordFreq[i]) {
                  return false;
              }
          }
          return true;
      }
    

Complexity Analysis

  • Time Complexity: O(N + M)
    • N: Total characters across all strings in words1
    • M: Total characters across all strings in words2
  • Space Complexity: O(n + m)
    • n: words1.length
    • m: words2.length

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class Solution {
    public List<String> wordSubsets(String[] words1, String[] words2) {
        // Array to store the maximum frequency of each character across all strings in `words2`
        int[] maxFreq = new int[26];

        // calculate maxFreq of each character across all strings in `words2`
        for (String word : words2) {
            int[] currentWordFreq = new int[26];

            for (char ch : word.toCharArray()) {
                currentWordFreq[ch - 'a']++;

                // update maxFreq for each character
                maxFreq[ch - 'a'] = Math.max(maxFreq[ch - 'a'], currentWordFreq[ch - 'a']);
            }
        }

        // storing universal strings
        List<String> universalWords = new ArrayList<>();

        for (String word : words1) {
            // frequency array for the current word in words1
            int[] wordFreq = new int[26];

            for (char ch : word.toCharArray()) {
                wordFreq[ch - 'a']++;
            }

            // check if the word is universal
            if (isUniversal(wordFreq, maxFreq)) {
                universalWords.add(word);
            }
        }

        return universalWords;
    }

    // method to check if a word is universal
    private boolean isUniversal(int[] wordFreq, int[] maxFreq) {
        // verify if `wordFreq` satisfies the `maxFreq` for all characters
        for (int i = 0; i < 26; i++) {
            // `maxFreq[i]` is minimum frequency we need for `wordFreq[i]` 
            if (maxFreq[i] > wordFreq[i]) {
                return false;
            }
        }
        return true;
    }
}
This post is licensed under CC BY 4.0 by the author.