Saturday, August 31, 2019

Leetcode 1178. Number of Valid Words for Each Puzzle

https://leetcode.com/problems/number-of-valid-words-for-each-puzzle/description/

With respect to a given puzzle string, a word is valid if both the following conditions are satisfied:
  • word contains the first letter of puzzle.
  • For each letter in word, that letter is in puzzle.
    For example, if the puzzle is "abcdefg", then valid words are "faced", "cabbage", and "baggage"; while invalid words are "beefed" (doesn't include "a") and "based" (includes "s" which isn't in the puzzle).
Return an array answer, where answer[i] is the number of words in the given word list words that are valid with respect to the puzzle puzzles[i].

Example :
Input: 
words = ["aaaa","asas","able","ability","actt","actor","access"], 
puzzles = ["aboveyz","abrodyz","abslute","absoryz","actresz","gaswxyz"]
Output: [1,1,3,2,4,0]
Explanation:
1 valid word for "aboveyz" : "aaaa" 
1 valid word for "abrodyz" : "aaaa"
3 valid words for "abslute" : "aaaa", "asas", "able"
2 valid words for "absoryz" : "aaaa", "asas"
4 valid words for "actresz" : "aaaa", "asas", "actt", "access"
There're no valid words for "gaswxyz" cause none of the words in the list contains letter 'g'.

Constraints:
  • 1 <= words.length <= 10^5
  • 4 <= words[i].length <= 50
  • 1 <= puzzles.length <= 10^4
  • puzzles[i].length == 7
  • words[i][j]puzzles[i][j] are English lowercase letters.
  • Each puzzles[i] doesn't contain repeated characters.

Notes:

The key to this question is bit masking and recording. Since the words' length and puzzles' length are very long, a no-brainer method cannot pass the largest test case.

Some key information:
1): the size of each puzzles[i] is very short, and unique;
2): if a letter shows up in the words[i], then it is required to show up in puzzles[i] too; otherwise, it cannot be counted in;
3): from 2), the repeated letters in words[i] does not play a role. Thus, we can simply convert the string to a integer.

So we just need first to count the frequency of each words[i]. Then is the key: we will not go through the counting list for each puzzles[i] (which is too slow), instead, we will generate each sub-set (needs containing the first letter) of puzzles[i], then add the frequency recording previously together.

How to generate all the sub-set of a string or array, check this post.

See the code below:

class Solution {
public:
    vector<int> findNumOfValidWords(vector<string>& words, vector<string>& puzzles) {
        vector<int> res;
        unordered_map<int, int> mp; //count the frequency of the string in words
        for(auto &w : words) {
            int num = 0;
            for(auto &a : w) num |= 1<<(a-'a');
            ++mp[num];
        }
        for(auto &p : puzzles) {
            int ct = 0, len = p.size();
            for(int i=0; i<(1<<(len-1)); ++i) {//the first one is always in
                int mk = 1<<(p[0] - 'a');
                for(int j=1; j<len; ++j){
                    if(i & (1<<(j-1))) mk |= 1<<(p[j]-'a');
                }
                ct += mp[mk];
            }
            res.push_back(ct);
        }
        return res;
    }
};

No comments:

Post a Comment