We are given two arrays A and B of words.  Each word is a string of lowercase letters.
Now, say that word b is a subset of word a if every letter in b occurs in a, including multiplicity.  For example, "wrr" is a subset of "warrior", but is not a subset of "world".
Now say a word a from A is universal if for every b in B, b is a subset of a. 
Return a list of all universal words in A.  You can return the words in any order.
 



Example 1:
Input: A = ["amazon","apple","facebook","google","leetcode"], B = ["e","o"]
Output: ["facebook","google","leetcode"]


Example 2:
Input: A = ["amazon","apple","facebook","google","leetcode"], B = ["l","e"]
Output: ["apple","google","leetcode"]


Example 3:
Input: A = ["amazon","apple","facebook","google","leetcode"], B = ["e","oo"]
Output: ["facebook","google"]


Example 4:
Input: A = ["amazon","apple","facebook","google","leetcode"], B = ["lo","eo"]
Output: ["google","leetcode"]


Example 5:
Input: A = ["amazon","apple","facebook","google","leetcode"], B = ["ec","oc","ceo"]
Output: ["facebook","leetcode"]

 
Note:

1 <= A.length, B.length <= 10000
1 <= A[i].length, B[i].length <= 10
A[i] and B[i] consist only of lowercase letters.
All words in A[i] are unique: there isn't i != j with A[i] == A[j].

Difficulty: interview

Starter code:

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        

Solutions:
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        s = set(A)
        letters_required = {}
        for i in B:
            for j in i:
                count = i.count(j)
                if j not in letters_required or count > letters_required[j]:
                    letters_required[j] = count

        for i in A:
            for j in letters_required:
                if i.count(j) < letters_required[j]:
                    s.remove(i)
                    break
        return list(s)

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        ans=[]
        word={}
        for i in B:
            for j in i:
                if(j not in word):
                    word[j]=i.count(j)
                else:
                    if(i.count(j)>word[j]):
                        word[j]=i.count(j)
                        
        
      
        
        for i in A:
            x=0
            for k in word:
                if(word[k]>i.count(k)):
                    x=1
                    break;
                
            if(x!=1):
                
                ans.append(i)        
               
            
                
                   
                        
                    
                        
             
                    
                 
         
              
                
              
                    
        return ans               
       
               
                  
                      

                        
                        
            


class Solution(object):
    def wordSubsets(self, A, B):
        \"\"\"
        :type A: List[str]
        :type B: List[str]
        :rtype: List[str]
        \"\"\"
        s = set(A)
        letters_required = {}
        for i in B:
            for j in i:
                count = i.count(j)
                if j not in letters_required or count > letters_required[j]:
                    letters_required[j] = count

        for i in A:
            for j in letters_required:
                if i.count(j) < letters_required[j]:
                    s.remove(i)
                    break
        return list(s)

from collections import Counter as di
class Solution:
    def wordSubsets(self, a: List[str], b: List[str]) -> List[str]:
        d = di()
        ans = list()
        for i in b:
            d2 = di(i)
            for k, v in d2.items():
                if d[k] < d2[k]:
                    d[k] = v
        
        for i in a:
            if len(d - di(i)) == 0:
                ans.append(i)
        return ans

from collections import Counter 

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        s = Counter()
        for b in B: 
            s = s | Counter(b)
            
        words = []
        def is_universal(word: str):
            word_counts = Counter(word)
            if len(word) < len(s): 
                return False
            for k, v in list(s.items()): 
                if k not in word_counts: 
                    return False 
                if word_counts[k] < v: 
                    return False 
            return True
        
        for word in A: 
            if is_universal(word): 
                words.append(word)
        
        return words
            


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        subset = reduce(operator.or_, (Counter(w) for w in B))
        return [a for a in A if all(a.count(c) >= subset[c] for c in subset.keys())]

from collections import Counter

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        h = {}
        for word in B:
            temp = Counter(word)
            for key, value in temp.items():
                if key not in h:
                    h[key] = value
                else:
                    h[key] = max(h[key], value)
        res = []
        for word in A:
            temp = Counter(word)
            suitable = True
            for key, value in h.items():
                if not (key in temp and value <= temp[key]):
                    suitable = False
                    break
            if suitable:
                res.append(word)
        return res

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        if len (B) == 0:
            return A
        
        from collections import Counter
        
        cb = Counter()
        for b in B:
            for char in b:
                cb[char] = max (cb[char], b.count(char))

        res = []    
        for a in A:
            
            if all (a.count (c) >= cb[c] for c in cb.keys()):
                res.append (a)
        
        return res

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        max_set = {}
        result = []
        
        for i in B:
            for char in i:
                if char not in max_set:
                    max_set[char] = i.count(char)
                else:
                    max_set[char] = max(i.count(char), max_set[char])
        
        for word in A:
            flag = True
            for char in max_set:
                if word.count(char) < max_set[char]:
                    flag = False
                    break
            if flag:
                result.append(word)
            else:
                pass
            
        
        return result
                    


from collections import Counter
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        res = set()
        B_count = Counter()
        for b in B:
            word_count = Counter(b)
            for c, v in word_count.items():
                B_count[c] = max(B_count[c], v)
        for a in A:
            if len(B_count - Counter(a)) == 0:
                res.add(a)
        return list(res)

class Solution:
    
    def subset(self, a,b):
        base = [0] * 26
        i = 0
        while i < len(a) or i < len(b):
            if i < len(a) and i < len(b):
                base[ord(a[i])-97] -= 1
                base[ord(b[i])-97] += 1
            elif i < len(a):
                base[ord(a[i])-97] -= 1
            else: return False
            i += 1
        
        for c in base:
            if c > 0: return False
        
        return True
    
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        B = list(set(B))
        base = [0] * 26
        for b in B:
            cur = [0]*26
            for c in b:
                cur[ord(c)-97] += 1
            for i in range(len(base)):
                base[i] = max(base[i], cur[i])
        
        ret = []
        for a in A:
            cur = [0]*26
            for c in a:
                cur[ord(c)-97] += 1
            add = True
            for i in range(len(base)):
                if base[i] > cur[i]:
                    add = False
                    break
            if add: ret.append(a)
        
        return ret
            


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        ctr = collections.Counter()
        for word in B:
            ctr2 = collections.Counter(word)
            # ctr.setdefault()
            for key, val in ctr2.items():
                ctr[key] = max(val, ctr[key])
        ctr3 = collections.Counter()
        # for key, val in collections.Counter(
        res = []
        for w in A:
            ctr3 = collections.Counter(w)
            newCtr = collections.Counter()
            for key, val in ctr3.items():
                if key in ctr:
                    newCtr[key] = min(val, ctr[key])
            if newCtr == ctr:
                res.append(w)
        return res

from collections import defaultdict
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        b_dict = defaultdict(int)
        for word in B:
            curr = defaultdict(int)
            for char in word:
                curr[char] += 1
            for char in curr:
                b_dict[char] = max(b_dict[char], curr[char])
        
        universal = []
        for word in A:
            curr = defaultdict(int)
            for char in word:
                curr[char] += 1
            
            is_subset = True
            for char in b_dict:
                if char not in curr or curr[char] < b_dict[char]:
                    is_subset = False
                    break
            if is_subset:
                universal.append(word)
                
        return universal
    
        # len(A) = n, len(B) = m, word len = 10, time: 10m + 10n + 26 = O(m + n)
    


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        ans=[]
        word={}
        for i in B:
            for j in set(i):
                c = i.count(j)
                if(j not in word):
                    word[j]=c
                else:
                    if(c>word[j]):
                        word[j]=c
                        
        for i in A:
            x=0
            for k in word:
                if(word[k]>i.count(k)):
                    x=1
                    break;
                
            if(x!=1):
                ans.append(i)
            
        return ans

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        cnt = collections.Counter
        bCnt = cnt()
        for b in B:
            bCnt |= cnt(b)
        return [a for a in A if not (bCnt - cnt(a))]

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        # 1)
        i, A2, seen = 0, [], set()
        while i < len(A):
            if A[i] not in seen:
                seen.add(A[i])
                dct = {}
                for char in A[i]:
                    if char in dct:
                        dct[char] += 1
                    else:
                        dct[char] = 1
                A2.append(dct)
                i += 1
            else:
                A.pop(i)
                
        i, seen = 0, set()
        while i < len(B):
            if B[i] not in seen:
                seen.add(B[i])
                dct = {}
                for char in B[i]:
                    if char in dct:
                        dct[char] += 1
                    else:
                        dct[char] = 1
                B[i] = dct
                i += 1
            else:
                B.pop(i)
        
        # 2) merge all the dicts of B into one dict
        while len(B) > 1:
            for key in B[1]:
                if key in B[0]:
                    B[1][key] = max(B[1][key], B[0][key])
            for key in B[0]:
                if key not in B[1]:
                    B[1][key] = B[0][key]
            B.pop(0)
        B_dct = B[0]
        
        # 3)
        ans, A_len, B_len = [], len(A), len(B)
        for i in range(A_len):
            isSubset = True
            for key in B_dct:
                if key not in A2[i] or (key in A2[i] and B_dct[key] > A2[i][key]):
                    isSubset = False
                    break
            if isSubset:
                ans.append(A[i])
        return ans

import collections


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        b_cnt = collections.Counter()
        for b in B:
            b_cnt |= collections.Counter(b)
            
        res = []
        for a in A:
            if collections.Counter(a) & b_cnt == b_cnt:
                res.append(a)
        return res

from collections import Counter
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        subset = Counter()
        for b in B:
            for k, v in Counter(b).items():
                subset[k] = max(subset[k], v)
        result = filter(lambda a: True if not subset-Counter(a) else False, A)
        return list(result)

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:

        w1_set = {}
        for word in B:
            new_w1_set = {}
            for c in word:
                if c not in new_w1_set:
                    new_w1_set[c] = 0
                new_w1_set[c] += 1
                
            for c in new_w1_set:
                if c not in w1_set:
                    w1_set[c] = new_w1_set[c]
                else:
                    w1_set[c] = max(w1_set[c], new_w1_set[c])
        
        output = []
        for word in A:
            w2_set = {}
            for c in word:
                if c not in w2_set:
                    w2_set[c] = 0
                w2_set[c] += 1
            
            check = True
            for c in w1_set:
                if (c not in w2_set) or (w1_set[c] > w2_set[c]):
                    check = False
                    break
            
            if check:
                output.append(word)
            
        return output


import collections
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        def aggregate_b(B):
            max_occurences = collections.defaultdict(list)
            for subset in B:
                letter_count = collections.Counter(subset)
                for letter, count in list(letter_count.items()):
                    if not max_occurences[letter] or count > max_occurences[letter]:
                        max_occurences[letter] = count
            return max_occurences

        result = []
        max_letter_occurences = aggregate_b(B)
        for word in A:
            letter_count = max_letter_occurences.copy()
            for letter in word:
                if letter in letter_count:
                    letter_count[letter] -= 1
                    if letter_count[letter] == 0:
                        del letter_count[letter]
            if not letter_count:
                result.append(word)
                
        return result




from collections import Counter
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        total_count_B = Counter()
        for s in B:
            total_count_B |= Counter(s)
                    
        return [a for a in A if Counter(a) & total_count_B == total_count_B]
            


from collections import Counter
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        b_hash = {}
        ans = []
        for i in B:
            for j in set(i):
                if j in b_hash:
                    b_hash[j] = max(i.count(j), b_hash[j])
                else:
                    b_hash[j] = i.count(j)
        
        for wrd in A:
            new_b_hash = b_hash.copy()
            for i in set(wrd):
                if i in b_hash:
                    new_b_hash[i] -= wrd.count(i)
            value_flag = True
            for i in list(new_b_hash.values()):
                if i > 0:
                    value_flag = False
                    break
            if value_flag:
                ans.append(wrd)                
            
        return ans
                
                    
            

        


from collections import Counter

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        universal_words = []
        required_counts = {}
        for pattern in B:
            for char in pattern:
                char_sum = sum(1 for i in pattern if i == char)
                if char not in required_counts or required_counts[char] < char_sum:
                    required_counts[char] = char_sum
        print(required_counts)
        for word in A:
            universal = True
            for char in required_counts:
                char_count = sum(1 for i in word if i == char)
                if char_count < required_counts[char]:
                    universal = False
            if universal:
                universal_words.append(word)
        return universal_words

from collections import Counter


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        \"\"\"
        https://leetcode.com/problems/word-subsets/discuss/175854/C%2B%2BJavaPython-Straight-Forward
        \"\"\"

        count = Counter()

        for b in B:
            count |= Counter(b)

        return [a for a in A if (Counter(a) & count) == count]


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        ans=[]
        word={}
        for i in B:
            for j in set(i):
                if(j not in word):
                    word[j]=i.count(j)
                else:
                    if(i.count(j)>word[j]):
                        word[j]=i.count(j)
                        
        for i in A:
            x=0
            for k in word:
                if(word[k]>i.count(k)):
                    x=1
                    break;
                
            if(x!=1):
                ans.append(i)
            
        return ans

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        lc = [0] * 26
        for b in B:
            for c, count in collections.Counter(b).items():
                i = ord(c) - ord('a')
                lc[i] = max(lc[i], count)
        ans = []
        
        for a in A:
            uni = True
            cter = collections.Counter(a)
            for c, count in zip(string.ascii_lowercase, lc):
                if count > cter[c]:
                    uni = False
                    break
            if uni:
                ans.append(a)
        return ans

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        answer = list()
        b_counter = collections.Counter()
        for word in B:
            counter = collections.Counter(word)
            for letter, count in counter.items():
                b_counter[letter] = max(b_counter[letter], count)

        for word in A:
            counter = collections.Counter(word)
            if all(l in counter and counter[l] >= count for l, count in b_counter.items()):
                answer.append(word)
        
        return answer

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        from collections import Counter
        
        freq = {word: Counter(word) for word in A}
        queries = {word: Counter(word) for word in B}
        query = {chr(i): max(queries[word].get(chr(i), 0) for word in queries) for i in range(ord('a'), ord('z') + 1)}
        
        ans = set()
        
        for k in list(freq.keys()):
            flag = 1
            for ch in query:
                if query[ch] > freq[k].get(ch, 0):
                    flag = 0
                    break
            
            if flag: ans.add(k)
        
        return list(ans)
            
            
        


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        # So we don't process the same word twice
        seen = set()
        # Freq of union of all words in B
        freq_B = [0] * 26
        for word in B:
            if word not in seen:
                seen.add(word)

                freq_cur = [0] * 26
                for c in word:
                    freq_cur[ord(c)-ord('a')] += 1

                for i in range(26):
                    freq_B[i] = max(freq_B[i], freq_cur[i])

        ans = []
        for word in A:
            freq_A = [0] * 26
            for c in word:
                freq_A[ord(c)-ord('a')] += 1

            broke_early = False
            for i in range(26):
                if freq_A[i] < freq_B[i]:
                    broke_early = True
                    break
            if broke_early:
                continue
            ans += [word]
        return ans

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        b_union_ctr = Counter()
        for b_element in B:
            b_union_ctr |= Counter(b_element)
        output = []
        for a_element in A:
            a_count = Counter(a_element)
            if len(b_union_ctr - a_count) == 0:
                output.append(a_element)
        return output


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        # Combine counts in B to save time
        count = collections.Counter()
        for b in B:
            # | keeps bigger number
            count |= collections.Counter(b)
        return [a for a in A if (Counter(a) & count) == count]

from functools import reduce
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        cntB = [Counter(b) for b in B]
        sumB = reduce(lambda x, y: x | y, cntB)
        ans = []
        for a in A:
            cnt = Counter(a)
            if all(sumB[s] <= cnt[s] for s in sumB):
                ans.append(a)
        return ans


from collections import Counter


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        if len(B) == 0:
            return []
        ans = []
        ca = [Counter(a) for a in A]
        cb = Counter(B[0])
        for i in range(1, len(B)):
            lb = Counter(B[i])
            for c in lb:
                cb[c] = max(cb[c], lb[c])
            
        for i in range(len(A)):
            isUniv = True
            if len(cb - ca[i]) > 0:
                continue
            ans.append(A[i])
        return ans
                


class Solution:
    def issubset(self, s: str, t:str) -> bool:
        dic = dict()
        for i in range(len(t)):
            dic[t[i]] = dic.get(t[i],0) + 1
        result = True
        i = 0
        while (i < len(s)) and result:
            if (s[i] not in list(dic.keys())) or (dic[s[i]] < 1):
                result = False
            else:
                dic[s[i]] -= 1
                i += 1
                
        return result
    
    def joining(self, B: List[str]) -> str:
        result = dict()
        for i in range(len(B)):
            word = B[i]
            temp = dict()
            for j in range(len(word)):
                temp[word[j]] = temp.get(word[j],0) + 1
                
            for (k,v) in list(temp.items()):
                if (k not in list(result.keys())) or (result[k] < v):
                    result[k] = v
                    
        res = ''
        for (k,v) in list(result.items()):
            res += k*v
        return res
            
        
                
                
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        res = []
        union = self.joining(B)
        for word in A:
            if self.issubset(union,word) == True:
                res.append(word)
                
        return res


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        maxcb = Counter()
        for b in B:
            maxcb |= Counter(b)
        return [a for a in A if Counter(a) & maxcb == maxcb]     


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        dic = {}
        out = []
        
        for word in B:
            dicWord = {}
            for letter in word:
                if not letter in dicWord:
                    dicWord[letter] = 1
                else:
                    dicWord[letter] += 1
            for letter in dicWord:
                if not letter in dic:
                    dic[letter] = dicWord[letter]
                else:
                    dic[letter] = max(dic[letter], dicWord[letter])
                    
        for word in A:
            dicWord = {}
            universal = True
            for letter in word:
                if letter in dicWord:
                    dicWord[letter] += 1
                else:
                    dicWord[letter] = 1
            
            for letter in dic:
                if not letter in dicWord:
                    universal = False
                    break
                if dic[letter] > dicWord[letter]:
                    universal = False
                    break                    
                        
            if not universal:
                continue
            else:
                out += [word]
        
        return out
            


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        need = Counter()
        
        for word in B:
            word_count = Counter(word)
            for k, v in list(word_count.items()):
                need[k] = max(need[k], v)

        def is_subset(word):
            word_count = Counter(word)
            needed = need.copy()
            
            for c in need:
                word_count[c] -= needed[c]
                if word_count[c] < 0:
                    return False
            
            return True
            
        res = []
        for word in A:
            if is_subset(word):
                res.append(word)
        
        return res



class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        res = []
        max_b = [0] * 26
        for i in range(len(B)):
            local_b = [0] * 26
            for c in B[i]:
                local_b[ord(c) - 97] += 1
            for i in range(26):
                max_b[i] = max(max_b[i], local_b[i])
        for i in range(len(A)):
            local_a = [0] * 26
            for c in A[i]:
                local_a[ord(c) - 97] += 1
            for k in range(26):
                if local_a[k] < max_b[k]:
                    break
                if k == 25:
                    res.append(A[i])
        return res

class Solution:
    def wordSubsets(self, A: 'List[str]', B: 'List[str]') -> 'List[str]':
        def count(word):
            ans = [0] * 26
            for c in word:
                ans[ord(c) - ord('a')] += 1
            return ans
        
        # simplify B
        bmax = [0] * 26
        for b in B:
            ls = count(b)
            for i in range(26):
                bmax[i] = max(bmax[i], ls[i])
        
        ans = []
        for a in A:
            ls = count(a)
            for i in range(26):
                if ls[i] < bmax[i]:
                    break
            else: # execute if the for-loop ends without break
                ans.append(a)
        return ans

from collections import Counter

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        c = Counter()
        for b in B:
            c = c | Counter(b)
            
        return [a for a in A if Counter(a) & c == c]

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        b_representation = [0]*26
        
        def str2list(s):
            li = [0]*26
            for c in s:
                li[ord(c)-ord('a')] +=1
            return li
        
        def is_greater(li1, li2):
            for i in range(26):
                if li1[i] < li2[i]:
                    return False
            return True
        
        for s in B:
            b_representation = [max(tmp1, tmp2) for tmp1, tmp2 in zip(b_representation, str2list(s))]
        res = []
        for s in A:
            if is_greater(str2list(s),b_representation):
                res.append(s)
            
        return res

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        ret = []
        bx=Counter()
        for ib in B:
            bx |= Counter(ib)
        
        for ia in A:
            cx=Counter(ia) & bx
            if(cx == bx):
                ret.append(ia)
        
        return ret

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        counter = [0]*26
        res = []
        
        for b in B:
            temp = [0]*26
            
            for c in b:
                temp[ord(c)-ord('a')] += 1
                
            for i in range(26):
                counter[i] = max(counter[i], temp[i])

        for a in A:
            temp = [0]*26
            
            for c in a:
                k = ord(c)-ord('a')
                temp[k] += 1
            
            
            for i in range(26):
                if temp[i]<counter[i]:
                    break
            else:
                res.append(a)
                
        return res


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        universal = Counter()
        for b in B:            
            universal |= Counter(b)
        
        ans = []
        for a in A:
            c = Counter(a)
            c.subtract(universal)
            if all(v >= 0 for v in c.values()):
                ans.append(a)
        
        return ans

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        universal = Counter()
        for b in B:            
            universal |= Counter(b)
            # for char, count in Counter(b).items():
            #     universal[char] = max(universal[char], count)
        
        ans = []
        for a in A:
            c = Counter(a)
            c.subtract(universal)
            if all(v >= 0 for v in c.values()):
                ans.append(a)
        
        return ans

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        cnt = [0] * 26
        for b in B:
            cnt1 = [0] * 26
            for c in b:
                cnt1[ord(c) - 97] += 1
            for i, j in enumerate(cnt1):
                cnt[i] = max(cnt[i], j)
        result = []
        for a in A:
            cnt1 = [0] * 26
            for c in a:
                cnt1[ord(c) - 97] += 1
            if all(j <= cnt1[i] for i, j in enumerate(cnt)):
                result.append(a)
        return result        


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        temp = {}
        require = {}
        universal = []
        for b in B:
            temp.clear()
            for c in b:
                if c in temp:
                    temp[c] += 1
                else:
                    temp[c] = 1
            for k in temp:
                if k not in require or require[k] < temp[k]:
                    require[k] = temp[k]
        
        for a in A:
            toAdd = True
            temp.clear()
            for c in a:
                if c in temp:
                    temp[c] += 1
                else:
                    temp[c] = 1
            for k in require:
                if k not in temp or require[k] > temp[k]:
                    toAdd = False
                    break
            if toAdd:
                universal.append(a)
            
        
        return universal

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        res = []
        bwdict = Counter(B[0])
        for bw in B[1:]:
            tmpCounter = Counter(bw)
            for key,val in list(tmpCounter.items()):
                wcnt = bwdict.get(key,-1)
                if val > wcnt:
                    bwdict[key] = val
        print(bwdict)
            
        for word in A:
            tmpW = (word + '.')[:-1]
            wdict = Counter(word)
            isSub = []
            for key,val in list(bwdict.items()):
                wcnt = wdict.get(key,-1)
                if val <= wcnt:
                    isSub.append(True)
                else:
                    isSub.append(False)
            if all(isSub):
                res.append(word)
                
        return res


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        if not A:
            return []
        word_map_B = self.createMapWordB(B)
        res = []
        
        for word in A:
            if self.searchWord(word, word_map_B):
                res.append(word)
        return res
    
    def createMapWordB(self, B):
        # Simplify B to be the combination of all letters
        max_B = [0] * 26
        for b in B:
            temp_B = self.createSingleWordCount(b)
            for i in range(26):
                max_B[i] = max(max_B[i], temp_B[i])
        return max_B
        
    def createSingleWordCount(self, word):
        res = [0] * 26
        for c in word:
            idx = ord(c) - ord('a')
            res[idx] += 1
        return res
        
    def searchWord(self, word, max_B):
        word_count = self.createSingleWordCount(word)
        for i in range(26):
            if word_count[i] < max_B[i]:
                return False
        return True

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        count = collections.Counter()
        for b in B:
            count = count | collections.Counter(b)
        return [a for a in A if Counter(a) & count == count]
            


from functools import reduce
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        alphabet = reduce(lambda x, y: Counter(y) | x, B, Counter())
        return [a for a in A if (Counter(a) & alphabet) == alphabet]


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        def count(word):
            ans = [0] * 26
            for c in word:
                ans[ord(c) - ord('a')] += 1
            return ans
        
        # simplify B
        bmax = [0] * 26
        for b in B:
            ls = count(b)
            for i in range(26):
                bmax[i] = max(bmax[i], ls[i])
        
        ans = []
        for a in A:
            ls = count(a)
            for i in range(26):
                if ls[i] < bmax[i]:
                    break
            else: # execute if the for-loop ends without break
                ans.append(a)
        return ans


from collections import Counter
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        res = []
        b_word = [0] * 26
        
        for word in B:
            for idx, count in enumerate(self.create_char_set(word)):
                b_word[idx] = max(b_word[idx], count)
        
        for word in A:
            a_word = self.create_char_set(word)
            idx = 0
            while idx < len(b_word) and a_word[idx] >= b_word[idx]:
                idx += 1
            if idx == len(b_word):
                res.append(word)
                
        return res
        
        
    
    def create_char_set(self, word):
        char_set = [0] * 26
        for char in word:
            char_set[ord(char) - ord('a')] += 1
        return char_set


class Solution:
    def wordSubsets(self, A, B):
        def count_word(word):
            a = [0] * 26
            
            for c in word:
                a[ord(c) - ord(\"a\")] += 1
            
            return a
        
        max_count = [0] * 26
        
        for w in B:
            cur_count = count_word(w)
            max_count = [max(cur_count[i], max_count[i]) for i in range(len(cur_count))]
            
        ans = []
        for w in A:
            if all(x>=y for x,y in zip(count_word(w), max_count)):
                ans.append(w)
        
        return ans

class Solution(object):
    def wordSubsets(self, A, B):
        def count(word):
            ans = [0] * 26
            for letter in word:
                ans[ord(letter) - ord('a')] += 1
            return ans

        bmax = [0] * 26
        for b in B:
            for i, c in enumerate(count(b)):
                bmax[i] = max(bmax[i], c)

        ans = []
        for a in A:
            if all(x >= y for x, y in zip(count(a), bmax)):
                ans.append(a)
        return ans

from collections import defaultdict

class Solution:
    
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        result=[]
        if not A :
            return result
        if not B:
            return A
        C=[]
        for j in B:
                d=[0]*26    
                for ch in j:
                    d[ord(ch)-ord('a')]+=1
                C.append(d) 
        l=[0]*26
        # print(C)
        for j in C:
            for i in range(26):
                l[i]=max(l[i],j[i])
        # print(l)

        
        for i in A:
            d=list(l)
            for ch in i:
                if d[ord(ch)-ord('a')]>0:
                    d[ord(ch)-ord('a')] -=1
            if sum(d)==0:
                result.append(i)
                        
            
        return result
                    


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        from collections import Counter
        
        freq = {word: Counter(word) for word in A}
        queries = {word: Counter(word) for word in B}
        query = {chr(i): max(queries[word].get(chr(i), 0) for word in queries) for i in range(ord('a'), ord('z') + 1)}
        
        ans = []
        
        for k in list(freq.keys()):
            flag = 1
            for ch in query:
                if query[ch] > freq[k].get(ch, 0):
                    flag = 0
                    break
            
            if flag: ans.append(k)
        
        return ans
            
            
        


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        dic = {}
        for b in B:
            for char in b:
                dic[char] = max(dic.get(char, 0), b.count(char))
        
        res = []
        for a in A:
            if all(a.count(k) >= dic[k] for k in dic):
                res.append(a)
        return res
        
        
        
        
#https://leetcode.com/problems/word-subsets/discuss/659164/Python-90-with-comments-and-explanation


class Solution:
    def count(self, word):
        res = [0] * 26
        for item in word:
            tmp = ord(item) - ord('a')
            res[tmp] += 1
        return res
    
    def satisfy(self, item, bmax):
        tmp = self.count(item)
        for i in range(26):
            if tmp[i] < bmax[i]:
                return False
            
        return True
    
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        bmax = [0] * 26
        for item in B:
            for index, val in enumerate(self.count(item)):
                bmax[index] = max(bmax[index], val)
          
        res = []
        for item in A:
            if self.satisfy(item, bmax):
                res.append(item)
                
        return res

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        count = Counter()
        for b in B:
            count = count | Counter(b)
        return [a for a in A if Counter(a) & count == count]

from collections import Counter
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        res = []
        b_word = [0] * 26
        
        for word in B:
            for idx, count in enumerate(self.create_char_set(word)):
                b_word[idx] = max(b_word[idx], count)
        
        for word in A:
            a_word = self.create_char_set(word)
            if all(a >= b for a, b in zip(a_word, b_word)):
                res.append(word)
                
        return res
        
        
    
    def create_char_set(self, word):
        char_set = [0] * 26
        for char in word:
            char_set[ord(char) - ord('a')] += 1
        return char_set


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        count = collections.Counter()
        for b in B:
            # 两个Counter求或就是每一个元素key都更新到最大值。
            count = count | collections.Counter(b)
            # 两个Counter求与就是每一个元素key都更新到最小值。
        return [a for a in A if Counter(a) & count == count]

class Solution(object):
    def wordSubsets(self, A, B):
        def count(word):
            res = [0]*26
            for i in word:
                res[ord(i)-ord('a')] +=1
            return res
        b_max=[0]*26
        for b in B:
            bb=count(b)
            for w in range(26):
                b_max[w]=max(b_max[w],bb[w])
        ans = []
        for a in A:
            if all(x>=y for x,y in zip(count(a), b_max)):
                ans.append(a)
        return ans   
             
                        
        
        
#         def count(word):
#             ans = [0] * 26
#             for letter in word:
#                 ans[ord(letter) - ord('a')] += 1
#             return ans

#         bmax = [0] * 26
#         for b in B:
#             ls = count(b)
#             for i in range(len(ls)):
#                 bmax[i] = max(bmax[i], ls[i])
           
#             # for i, c in enumerate(count(b)):
#             #     bmax[i] = max(bmax[i], c)

#         ans = []
#         for a in A:
#             if all(x >= y for x, y in zip(count(a), bmax)):
#                 ans.append(a)
#         return ans


class Solution:
    
    def getCharFrequency(self, word):
        
        f = [0] * 26        
        for ch in word:            
            f[ord(ch)-ord('a')] += 1
        
        return f
            
        
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        result = []
        
        max_freq = [0]* 26
        
        for i in range(len(B)):
            curr_freq = self.getCharFrequency(B[i])
            
            for j in range(26):
                max_freq[j] = max(max_freq[j], curr_freq[j])
    
        
        for i in range(len(A)):
            curr_freq = self.getCharFrequency(A[i])
            
            valid = True
            
            for j in range(26):
                if max_freq[j] > curr_freq[j]:
                    valid = False
                    break
                
            if valid:
                result.append(A[i])
        
        return result
    
    
    


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        def count(word):
            result = [0]*26
            for letter in word:
                result[ord(letter)-ord('a')]+=1
            return result 
        
        bmax = [0]*26
        for b in B:
            for i, c in enumerate(count(b)):
                bmax[i] = max(bmax[i],c)
                
        result = []
        for a in A:
            if all(x >= y for x, y in zip(count(a), bmax)):
                result.append(a)
        
        return result 

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        def count(s):
            cnt = [0]*26
            for c in s:
                cnt[ord(c) - ord('a')] += 1
            return cnt
        
        cnt = [0]*26
        
        for b in B:
            bcnt = count(b)
            for i,c in enumerate(bcnt):
                cnt[i] = max(cnt[i],c)
                
        ans = []
        for a in A:
            acnt = count(a)
            if all(x>=y for x,y in zip(acnt,cnt)):
                ans.append(a)
                
        return ans
        


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        d = {}
        for a in A:
            d[a] = Counter(a)
        cd = defaultdict(int)
        for b in B:
            for i in Counter(b):
                cd[i] = max(cd[i], Counter(b)[i])
        ret = []
        for k in d:
            t = True
            for c in cd:
                if c not in k or d[k][c] < cd[c]:
                    t = False
                    break
            if t:
                ret.append(k)
        return ret

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        subset = {}
        for b in B:
            for char in b:
                subset[char] = max(subset.get(char, 0), b.count(char))
        return [a for a in A if all(a.count(c) >= subset[c] for c in subset.keys())]

from collections import Counter
class Solution:
     def wordSubsets(self, A, B):
        count = collections.Counter()
        for b in B:
            count = count | collections.Counter(b)
        return [a for a in A if Counter(a) & count == count]

import collections


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        dp = [0] * 26
        for b in B:
            dp = [max(i, j) for i, j in zip(dp, self.bow(b))]
        print(dp)
            
        res = []
        for a in A:
            if not any([al < bl for al, bl in zip(self.bow(a), dp)]):
                res.append(a)
        return res
    
    def bow(self, text):
        d = [0] * 26
        for l in text:
            d[ord(l) - ord('a')] += 1
        return d

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        cover = [0] * 26
        for i in range(len(B)):
            max_cnt = [0] * 26
            for c in B[i]:
                max_cnt[ord(c) - ord('a')] += 1
            cover = [max(x, y) for x, y in zip(cover, max_cnt)]
        
        res = []
        for i in range(len(A)):
            cnt = [0] * 26
            for c in A[i]:
                cnt[ord(c) - ord('a')] += 1
            if all([x>=y for x, y in zip(cnt, cover)]):
                res.append(A[i])
        
        return res


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        # O(m + n); m and n is the total amount of chars in A and B
        def count(word):
            counter = [0] * 26
            for w in word:
                counter[ord(w) - ord(\"a\")] += 1
            return counter
            
        b_char_combine = [0] * 26
        for b in B:
            for i, c in enumerate(count(b)):
                b_char_combine[i] = max(b_char_combine[i], c)

        res = []
        for a in A:
            if all(x >= y for x, y in zip(count(a), b_char_combine)):
                res.append(a)

        return res
            

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        count = collections.Counter()
        for b in B:
            count = count | collections.Counter(b)
        return [a for a in A if Counter(a) & count == count]


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        cover = [0] * 26
        for i in range(len(B)):
            cnt = [0] * 26
            for c in B[i]:
                cnt[ord(c) - ord('a')] += 1
            cover = [max(x, y) for x, y in zip(cover, cnt)]
        
        res = []
        for i in range(len(A)):
            cnt = [0] * 26
            for c in A[i]:
                cnt[ord(c) - ord('a')] += 1
            if all([x>=y for x, y in zip(cnt, cover)]):
                res.append(A[i])
        
        return res


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        def count(word):
            ans = [0] * 26
            for letter in word:
                ans[ord(letter) - ord('a')] += 1
            return ans

        bmax = [0] * 26
        for b in B:
            for i, c in enumerate(count(b)):
                bmax[i] = max(bmax[i], c)

        ans = []
        for a in A:
            if all(x >= y for x, y in zip(count(a), bmax)):
                ans.append(a)
        return ans

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        def count(word):
            ans = [0]*26
            for letter in word:
                ans[ord(letter) - ord('a')] += 1
            return ans
            print(ans)
        
        bmax = [0]*26
        for b in B:
            for i, c in enumerate(count(b)):
                bmax[i] = max(bmax[i], c)
        
        ans = []
        for a in A:
            if all(x >= y for x, y in zip(count(a), bmax)):
                ans.append(a)
                
        return ans


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        A_dict = []
        B_dict = {} #final dictionary of B taking max of cnt
        ans = []
        for ww in A:
            temp = {}
            for ele in ww:
                if ele in temp:
                    temp[ele] +=1
                else:
                    temp[ele] =1
            A_dict.append(temp)
        for ww in B:
            temp = {}
            for ele in ww:
                if ele in temp:
                    temp[ele] +=1
                else:
                    temp[ele] =1
            for key,cnt in temp.items():
                if key in B_dict:
                    B_dict[key] = max(cnt,B_dict[key])
                else:
                    B_dict[key] = cnt
        for ind,ele in enumerate(A_dict):
            cur_dict = ele
            flag = True
            for key,cnt in B_dict.items():
                if key not in cur_dict or cur_dict[key]<cnt:
                    flag = False
                    break
            if flag:
                ans.append(A[ind])
        return ans

class Solution:
    def wordSubsets(self, A, B):
        '''
        :type A: list of str
        :type B: list of str
        :rtype: list of str
        '''
        b_count = [0] * 26

        # Collecting the constraints into a character mapping
        for word in B:
            tmp_count = self.count(word)

            for i in range(0, 26):
                b_count[i] = max(b_count[i], tmp_count[i])

        # Testing each character in A
        output = []
        for word in A:
            tmp_count = self.count(word)

            universal = True
            for i in range(0, 26):
                if tmp_count[i] < b_count[i]:
                    universal = False

            if universal:
                output.append(word)

        return output

    def count(self, word):
        output = [0] * 26

        for letter in word:
            idx = ord(letter) - ord(\"a\")
            output[idx] += 1

        return output



class Solution:
    
    
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        def count(word):
            ans = [0] * 26
            for letter in word:
                ans[ord(letter) - ord('a')] += 1
            return ans

        bmax = [0] * 26
        for b in B:
            for i, c in enumerate(count(b)):
                bmax[i] = max(bmax[i], c)

        ans = []
        for a in A:
            if all(x >= y for x, y in zip(count(a), bmax)):
                ans.append(a)
        return ans

from functools import reduce
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        c_b = reduce(operator.or_, (Counter(w) for w in B))
        return [a for a in A if not c_b-Counter(a)]


from collections import defaultdict
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        bMap = defaultdict(int)
        ans = []
        
        maxB = [0]*26
        
        for b in B:
            m = self.count(b)
            for i in range(len(m)):
                maxB[i] = max(maxB[i], m[i])
        
        for a in A:
            aMap = self.count(a)
            c = 0
            for i in range(len(aMap)):
                if aMap[i] >= maxB[i]:
                    c+=1
            if c == 26:
                ans.append(a)
        
        return ans
                    
            
    def count(self, arr):
        ans = [0]*26
        for ch in arr:
            ans[ord(ch)-ord('a')] += 1
        return ans

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        # Since a universal word needs to be superset for all words in B, we can combine all words in B
        #   to become a new word, and words in A only need to have this one single word as its subset
        
        # get a list of ints of length 26 to represent how many of each letter is in a word
        def countLetter(s):
            res = [0] * 26
            for c in s:
                res[ord(c) - ord('a')] += 1
            return res
        
        # get how many of each letter is in the combined letter of B, note that we only need the larger
        #   number if one char appears in two different words. Ex: 'lo' and 'loo' will become 'loo'
        b_count = [0] * 26
        for b in B:
            for i, c in enumerate(countLetter(b)):
                b_count[i] = max(b_count[i], c)
        
        # get all words x with count(x) greater than b_count in every character
        return [x for x in A if all([x >= y for x, y in zip(countLetter(x), b_count)])]

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        counter = [0] * 26
        for word in B:
            tmp = [0] * 26
            for c in map(lambda x : ord(x) - ord('a'), word):
                tmp[c] += 1
            for c in range(26):
                counter[c] = max(counter[c], tmp[c])
        
        ans = []
        for word in A:
            tmp = [0] * 26
            for c in map(lambda x : ord(x) - ord('a'), word):
                tmp[c] += 1
            if all(counter[c] <= tmp[c] for c in range(26)):
                ans.append(word)
        
        return ans

import collections

class Solution:
  def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
    A = [(a,collections.Counter(a)) for a in A]
    newB = {}
    for b in B:
      for x, c in collections.Counter(b).items():
          newB[x] = c if x not in newB else max(newB[x], c)
      
    B = newB

    return [a for a, counts in A
            if all(counts[x] >= c for x,c in B.items())
           ]

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        arr1 = []
        arr2 = []
        for x in A:
            arr1.append(collections.Counter(x))
        dic = collections.defaultdict(int)
        for y in B:
            t = collections.Counter(y)
            for c in t:
                dic[c] = max(dic[c], t[c])
        res = []
        
        def comp(i):
            for c in dic:
                if arr1[i][c] < dic[c]:
                    return False
            return True
        
        for i in range(len(A)):
            if comp(i):
                res.append(A[i])
        return res
                
            


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        LETTERS = 26
        
        base = ord('a')
        bCounts = [0 for _ in range(LETTERS)]
        
        for word in B:
            currCounts = [0 for _ in range(LETTERS)]
            
            for c in word:
                currCounts[ord(c) - base] += 1
                
            for i in range(LETTERS):
                bCounts[i] = max(currCounts[i], bCounts[i])
                
                
        result = []
        
        for word in A:
            currCounts = [0 for _ in range(LETTERS)]
            
            for c in word:
                currCounts[ord(c) - base] += 1
            
            valid = True
            for i in range(LETTERS):
                if currCounts[i] < bCounts[i]:
                    valid = False
                    break
                    
            if valid:
                result.append(word)
        
        
        
        return result


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        m = {}
        ret = []
        
        for b in B:
            each = {}
            for i in range(len(b)):
                each[b[i]] = each[b[i]] + 1 if b[i] in each else 1
                
            for k in each:
                if not k in m or m[k] < each[k]:
                    m[k] = each[k]
        
        for a in A:
            each = {}
            for i in range(len(a)):
                each[a[i]] = each[a[i]] + 1 if a[i] in each else 1
            
            isAdding = True
            for k in m:
                if not k in each or each[k] < m[k]:
                    isAdding = False
                    break
            
            if isAdding:
                ret.append(a)
                
        return ret


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        cnt=Counter()
        for i in B:
            cnt|=Counter(i)
        res=[]
        for i in A:
            if(not(cnt-Counter(i))): res.append(i)
        return res

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        # Since a universal word needs to be superset for all words in B, we can combine all words in B
        #   to become a new word, and words in A only need to have this one single word as its subset
        
        # get a list of ints of length 26 to represent how many of each letter is in a word
        def countLetter(s):
            res = [0] * 26
            for c in s:
                res[ord(c) - ord('a')] += 1
            return res
        
        # get how many of each letter is in the combined letter of B, note that we only need the larger
        #   number if one char appears in two different words. Ex: 'lo' and 'loo' will become 'loo'
        b_count = [0] * 26
        for b in B:
            for i, c in enumerate(countLetter(b)):
                b_count[i] = max(b_count[i], c)
        
        # get all words x with count(x) greater than b_count in every character
        return [x for x in A if all([a_count >= b_count for a_count, b_count in zip(countLetter(x), b_count)])]

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        def count(word) :
            ans = [0]*26
            for c in word:
                ans[ord(c)-ord('a')] += 1
            return ans
        
        B_dict = [0]*26
        
        for b in B :
            for i,c in enumerate(count(b)) :
                B_dict[i] = max(B_dict[i], c)

        ans = []

        for a in A:
            a_dict = count(a)
            
            flag = True
            for i, c in enumerate(count(a)) :
                if c<B_dict[i] :
                    flag = False
                    break
                    
            if flag :
                ans.append(a)
                
        return ans

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        A_counter = [Counter(a) for a in A]
        B_counter = [Counter(b) for b in B]
        b_merged = Counter()
        for chr_ in string.ascii_lowercase:
            b_merged[chr_] = max([bc[chr_] for bc in B_counter])
        
        def is_subset(ac, bc):
            for chr_ in string.ascii_lowercase:
                if ac[chr_] < bc[chr_]:
                    return False
            return True
        
        ans = []
        for i,ac in enumerate(A_counter):
            if is_subset(ac,b_merged):
                ans.append(A[i])
        
        return ans

from functools import reduce
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        c_a = [Counter(w) for w in A]
        c_b = reduce(lambda x, y: x | y, [Counter(w) for w in B])
        return [word for i, word in enumerate(A) if not c_b-c_a[i]]


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        min_require = [0]*26
        std_string = \"abcdefghijklmnopqrstuvwxyz\"
        for word in B:
            curr_char_freq = [0]*26
            for char in word:
                curr_char_freq[std_string.index(char)] += 1
            
            min_require = [max(x1, x2) for x1,x2 in zip(min_require, curr_char_freq)]
        
        result = []
        for word in A:
            curr_char_freq = [0]*26
            for char in word:
                curr_char_freq[std_string.index(char)] += 1
            
            if False in [curr_char_freq[i] >= min_require[i] for i in range(26)]:
                continue
            result.append(word)
        return result

from functools import reduce

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        b_cnt = reduce(lambda a, b: Counter(a) | Counter(b), B)
        a_cnt = Counter()
        result = []

        for word in A:
            for w in word:
                if w in b_cnt:
                    a_cnt[w] += 1
            if not b_cnt - a_cnt:
                result.append(word)
            a_cnt.clear()

        return result


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        ans,char_count,size_t = list(),Counter(),len(A)

        T_A,T_B= [Counter(a) for a in A],[Counter(b) for b in B]
        for k in T_B:
            for c in k:
                if k[c] > char_count[c]:
                    char_count[c] = k[c]    

        for i in range(len(T_A)):
            if not (char_count - T_A[i] == {}): 
                continue
            ans.append(A[i])
        return ans

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        output_list = []
        def count(word):
            res = [0] * 26
            for ch in word:
                pos = ord(ch) - ord('a')
                res[pos] = res[pos] + 1
            return res
        
        b_max = [0]*26
        for b in B:
            res_b = count(b)
            for i in range(26):
                b_max[i] = max(b_max[i], res_b[i])
        #print(b_max)
        for a in A:
            #Following is one simple way to compare two lists
            '''res_a = count(a)
            for i in range(26):
                if b_max[i] > res_a[i]:
                    break
                if i == 25:
                    output_list.append(a)'''
            #Following is another zip function way to compare two list(or iterators)
            if all(x>=y for x,y in zip(count(a), b_max)):
                output_list.append(a)            
        return output_list
                    
                
            
        
        


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        b_counts = {}
        for word in B:
            word_counts = {}
            for letter in word:
                if letter in word_counts:
                    word_counts[letter] += 1
                else:
                    word_counts[letter] = 1
            for letter in word_counts:
                if letter in b_counts:
                    b_counts[letter] = max(b_counts[letter], word_counts[letter])
                else:
                    b_counts[letter] = word_counts[letter]
        result = []
        for word in A:
            a_counts = {}
            for letter in word:
                if letter in a_counts:
                    a_counts[letter] += 1
                else:
                    a_counts[letter] = 1
            superset = True
            for key in b_counts:
                if key not in a_counts or b_counts[key] > a_counts[key]:
                    superset = False
                    break
            if superset:
                result.append(word)
        return result

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        b_cnt = reduce(lambda a, b: Counter(a) | Counter(b), B)
        return [a for a in A if not b_cnt - Counter(a)]

class Solution:
    
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        def conv(w):
            sol = [0 for _ in range(26)]
            for c in w:
                sol[ord(c)-ord('a')] += 1
            return sol
        
        bmax = [0 for _ in range(26)]
        for wb in B:
            for idx, cnt in enumerate(conv(wb)):
                bmax[idx] = max(bmax[idx], cnt)
                
        sol = []
        for wa in A:
            if all(a>=b for a, b in zip(conv(wa), bmax)):
                sol.append(wa)
        return sol
            
            
            


from collections import Counter

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        universal_word = Counter()
        # construct the universal word for B
        for b in B:
            universal_word |= Counter(b)
        
        result = []
        for a in A:
            # all of universal word is contained in a
            if not universal_word - Counter(a):
                result.append(a)
        
        return result


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        m = {}
        for i in range(26):
            letter = chr(ord('a')+i)
            m[letter] = 0
            for w in B:
                ct_curr_l = w.count(letter)
                # for l in w:
                #     if l == letter:
                #         ct_curr_l+=1
                m[letter] = max(m[letter],ct_curr_l)
        res = []
        for w in A:
            A_m = {}
            rt = True
            for l in w:
                if not l in A_m:
                    A_m[l] = 0
                A_m[l]+=1
            for k in m:
                if m[k]>0 and ((k not in A_m) or (A_m[k]<m[k])):
                    rt = False
            if rt == True:
                res.append(w)
        return res
                
                
                
                
                
                


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        def counter(c):
            listed = [0]*26
            for i in c:
                x=ord(i)-97
                listed[x]+=1
                
            return listed
        
        
        
        blist = [0]*26
        for b in B:
            temp_list = counter(b)
            for i in range(0,26):
                blist[i]= max(blist[i],temp_list[i])
        listed=blist
        l=[]
        
        for a in A:
            temp_list = counter(a)
            universal = True
            for i in range(0,26):
                if listed[i] > temp_list[i]:
                    universal = False
                    
            if universal:
                l.append(a)
        
        
        
        return l
    


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        if len (B) == 0:
            return A
        
        from collections import Counter
        
        cb = Counter (B[0])
        for i in range (1, len (B)):
            c = Counter (B[i])
            
            for ch in c.keys():
                cb[ch] = max (cb[ch], c[ch])

        res = []    
        for a in A:
            add = True
            ca = Counter(a)
            
            for keyB in cb.keys():
                if keyB not in ca or cb[keyB] > ca[keyB]:
                    add = False
            
            if add:
                res.append (a)
        
        return res

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        def count(word):
            ans = [0] * 26
            for letter in word:
                ans[ord(letter) - ord('a')] += 1
            return ans

        bmax = [0] * 26
        for b in B:
            for i, c in enumerate(count(b)):
                bmax[i] = max(bmax[i], c)

        ans = []
        for a in A:
            if all(x >= y for x, y in zip(count(a), bmax)):
                ans.append(a)
        return ans


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        count = collections.Counter()
        
        for b in B:
            count |= collections.Counter(b)
        
        return [a for a in A if collections.Counter(a) & count == count]

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        output_list = []
        def count(word):
            res = [0] * 26
            for ch in word:
                pos = ord(ch) - ord('a')
                res[pos] = res[pos] + 1
            return res
        
        b_max = [0]*26
        for b in B:
            res_b = count(b)
            for i in range(26):
                b_max[i] = max(b_max[i], res_b[i])
        #print(b_max)
        for a in A:
            #print(a)
            res_a = count(a)
            #prin
            for i in range(26):
                if b_max[i] > res_a[i]:
                    break
                if i == 25:
                    output_list.append(a)
        return output_list
                    
                
            
        
        


def f(c):
    return ord(c) - ord('a')

class Solution:
    def wordSubsets(self, A, B):
        
        def isSubSet(coverA, coverB):
            for i in range(26):
                if coverA[i] < coverB[i]:
                    return False
            return True
            
        coverB = [0] * 26
        for b in B:
            cover = [0] * 26
            for c in b:
                cover[f(c)] += 1
            for i in range(26):
                coverB[i] = max(coverB[i], cover[i])
            
        res = []
        for a in A:
            coverA = [0] * 26
            for c in a:
                coverA[f(c)] += 1
            if isSubSet(coverA, coverB):
                res.append(a)
        return res
                
                


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        subset = {}
        for b in B:
            for char in b:
                subset[char] = max(b.count(char), subset.get(char, 0))
        
        return [a for a in A if all(a.count(char) >= subset[char] for char in subset.keys())]

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        def count(s):
            res = [0]*26
            for x in s:
                res[ord(x)-ord('a')] += 1
            return res
        
        bmax = [0]*26
        for b in B:
            for i, c in enumerate(count(b)):
                bmax[i] = max(bmax[i], c)
        
        res = []
        for a in A:
            if all(x >= y for x, y in zip(count(a), bmax)):
                res.append(a)
        return res

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        m = {}
        for i in range(26):
            letter = chr(ord('a')+i)
            m[letter] = 0
            for w in B:
                ct_curr_l = 0
                for l in w:
                    if l == letter:
                        ct_curr_l+=1
                m[letter] = max(m[letter],ct_curr_l)
        res = []
        for w in A:
            A_m = {}
            rt = True
            for l in w:
                if not l in A_m:
                    A_m[l] = 0
                A_m[l]+=1
            for k in m:
                if m[k]>0 and ((k not in A_m) or (A_m[k]<m[k])):
                    rt = False
            if rt == True:
                res.append(w)
        return res
                
                
                
                
                
                


# time complexity: O(26*(A+B))
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        # 1st step, construct the minimal word which is a superset of all words in B
        letters = 'abcdefghijklmnopqrstuvwxyz'
        u = {c:0 for c in letters}
        for w in B:
            for c,f in list(Counter(w).items()): # char, frequency
                u[c] = max(u[c],f)
        
        #2nd step, find every word a in A such that u is a subset of a
        res = []
        for w in A:
            wc = Counter(w)
            if all(f <= wc[c] for c,f in list(u.items())):
                res.append(w)
        return res


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        m = {}
        for i in range(26):
            letter = chr(ord('a')+i)
            m[letter] = 0
            for w in B:
                ct_curr_l = w.count(letter)
                m[letter] = max(m[letter],ct_curr_l)
        res = []
        for w in A:
            A_m = {}
            rt = True
            for l in w:
                if not l in A_m:
                    A_m[l] = 0
                A_m[l]+=1
            for k in m:
                if m[k]>0 and ((k not in A_m) or (A_m[k]<m[k])):
                    rt = False
            if rt == True:
                res.append(w)
        return res
                
                
        
                
                
                


class Solution(object):
    def wordSubsets(self, A, B):
        def count(word):
            ans = [0] * 26
            for letter in word:
                ans[ord(letter) - ord('a')] += 1
            return ans

        bmax = [0] * 26
        for b in B:
            for i, c in enumerate(count(b)):
                bmax[i] = max(bmax[i], c)

        ans = []
        for a in A:
            if all(x >= y for x, y in zip(count(a), bmax)):
                ans.append(a)
        return ans
        


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        # Reduce to Single Word in B
        # Time  complexity: O(A + B) where A and B is the total amount of information in A and B respectively.
        # Space complexity: O(A.length + B.length)
        def count(word):
            ans = [0] * 26
            for letter in word:
                ans[ord(letter) - ord('a')] += 1
            return ans

        bmax = [0] * 26
        for b in B:
            for i, c in enumerate(count(b)):
                bmax[i] = max(bmax[i], c)

        ans = []
        for a in A:
            if all(x >= y for x, y in zip(count(a), bmax)):
                ans.append(a)

        return ans


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        ss = \"qwertyuiopasdfghjklzxcvbnm\"
        alltime = {}
        for i in ss:
            alltime[i] = 0
    
        def freq(s):
            temp = alltime.copy()
            for i in s:
                temp[i] += 1
            return temp
        
        a1 = []
        for i in A:
            a1.append(freq(i))
        
        a2 = []
        for i in B:
            a2.append(freq(i))
        
        for i in alltime:
            tt = 0
            for j in a2:
                tt = max(tt,j[i])
            alltime[i] = tt
        
        ans = []
        for i in range(len(a1)):
            flag = 0
            for j in alltime:
                if alltime[j] > a1[i][j]:
                    flag = 1
                    break
            if flag == 0:
                ans.append(A[i])
        return ans

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:

        def count(s):
            alpha = [0] * 26
            for w in s:
                alpha[ord(w) - ord('a')] += 1
            return tuple(alpha)
        
        def compare(a, b):
            for i in range(26):
                if b[i] > a[i]:
                    return False
            return True
        
        Acount = [count(a) for a in A]
        Bcount = [0] * 26
        
        for b in B:
            tmp = count(b)
            for i in range(26):
                Bcount[i] = max(Bcount[i], tmp[i])
        Bcount = tuple(Bcount)
        
        res = []
        
        for i in range(len(Acount)):
            if all(Acount[i][j] >= Bcount[j] for j in range(26)):
                res.append(A[i])
        return res

class Solution:
    def compare(self,d,d1):
        for i in d:
            if(i not in d1 or d[i]>d1[i]):
                return False
        return True
    
    def wordSubsets(self, a: List[str], b: List[str]) -> List[str]:
        bgroup = {}
        for i in b:
            d = {}
            for j in i:
                if j in d:
                    d[j]+=1
                else:
                    d[j] = 1
            for j in d:
                if j not in bgroup:
                    bgroup[j] = d[j]
                else:
                    bgroup[j] = max(bgroup[j],d[j])
        ans = []
        for i in a:
            d1 = {}
            for j in i:
                if j in d1:
                    d1[j]+=1
                else:
                    d1[j] = 1
            if(self.compare(bgroup,d1)):
                ans.append(i)
        return  ans

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        B_dt = collections.Counter(B[0])
        for b in B[1:]:
            B_dt = B_dt | collections.Counter(b)
        ans = []
        
        for a in A:
            if collections.Counter(a) & B_dt == B_dt:
                ans.append(a)
    
        return ans
            
        


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        def freq(s):
            dp=[0 for _ in range(26)]
            for i in s:
                dp[ord(i)-ord('a')]+=1
            return dp
        arr=[0 for _ in range(26)]
        for b in B:
            for i,j in enumerate(freq(b)):
                # print(i,j)
                arr[i]=max(arr[i],j)
        ans=[]
        for a in A:
            flag=1
            for i,j in enumerate(freq(a)):
                if arr[i]>j:
                    flag=0
            if flag:
                ans.append(a)
        return ans
                    
                    
            
                
            


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        superword = [0] * 26
        result = []
        for word in B:
            current = [0] * 26
            for ch in word:
                i = ord(ch) - ord('a')
                current[i] += 1
            
            for i in range(26):
                superword[i] = max(superword[i],current[i])
                
        
        for word in A:
            current = [0] * 26
            for ch in word:
                i = ord(ch) - ord('a')
                current[i] += 1
                
            found = True
            for i in range(26):
                if superword[i] > current[i]:
                    found = False
                    break
                    
            if found == True:
                result.append(word)
                
        return result


from collections import Counter

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        count = Counter()
        for b in B:
            count = count | Counter(b)
        return [a for a in A if Counter(a) & count == count]

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        def count(word):
            ans=[0]*26
            for i in word:
                ans[ord(i)-ord('a')]+=1
            return ans
        bMax=[0]*26
        for b in B:
            ls=count(b)
            for c in range(26):
                bMax[c]=max(bMax[c],ls[c])
        res=[]
        for i in A:
            ls=count(i)
            for c in range(26):
                if ls[c]<bMax[c]:
                    break
            else:
                res+=[i]
        return res

import collections
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        bCount = collections.Counter()
        for b in B:
            bCount = bCount | collections.Counter(b)
        res = []
        for a in A:
            if collections.Counter(a) & bCount == bCount:
                res += a,
                
        return res

class Solution:
    import collections
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        count = collections.Counter()
        for b in B:
            count = count | collections.Counter(b)
        return [a for a in A if Counter(a) & count == count]

class Solution(object):
    def wordSubsets(self, A, B):
        s = set(A)
        letters_required = {}
        for i in B:
            for j in i:
                count = i.count(j)
                if j not in letters_required or count > letters_required[j]:
                    letters_required[j] = count

        for i in A:
            for j in letters_required:
                if i.count(j) < letters_required[j]:
                    s.remove(i)
                    break
        return list(s)

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        \"\"\"def checkSubset(a, B):
            aDict = {}
            bDict = {}
            for b in B:
                bSet = set(b)
                for c in bSet:
                    if b.count(c) > a.count(c):
                        return False
            return True
        ret = []
        for a in A:
            if not checkSubset(a, B):
                continue
            else:
                ret.append(a)
        return ret\"\"\"
        \"\"\"def convertB(b):
            d = {}
            for c in b: 
                if c not in d:
                    d[c] = 1
                else:
                    d[c]+=1
            return d 
        for i in range(len(B)):
            B[i] = convertB(B[i])
        def convertA(a):
            d = {}
            for c in a:
                if c not in d:
                    d[c]=1
                else:
                    d[c]+=1
            return d
        convertedA = []
        for i in range(len(A)):
            convertedA.append(convertA(A[i]))
        
        def isGoodWord(aDict):
            for wordDict in B:
                for c in wordDict:
                    if c not in aDict or wordDict[c] > aDict[c]:
                        return False
            return True
        ret = []
        for i in range(len(convertedA)):
            if isGoodWord(convertedA[i]):
                ret.append(A[i])
        return ret\"\"\"
        bDict = {}
        def convertB(b):
            d = {}
            for c in b: 
                if c not in d:
                    d[c] = 1
                else:
                    d[c]+=1
            return d 
        for i in range(len(B)):
            B[i] = convertB(B[i])
        for d in B:
            for key in d:
                if key not in bDict:
                    bDict[key] = d[key]
                else:
                    if bDict[key] < d[key]:
                        bDict[key] = d[key]
        def convertA(a):
            d = {}
            for c in a:
                if c not in d:
                    d[c]=1
                else:
                    d[c]+=1
            return d
        def isGoodWord(aDict):
            for key in bDict:
                if key not in aDict or bDict[key] > aDict[key]:
                    return False
            return True
        
        convertedA = []
        
        ret = []
        for i in range(len(A)):
            convertedA.append(convertA(A[i]))
        for i in range(len(convertedA)):
            if isGoodWord(convertedA[i]):
                ret.append(A[i])
        return ret
            
        
            
                
            
        
                
                

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        max_count = {}
        for string in B:
            char_count = {}
            for ch in string:
                char_count[ch] = char_count.get(ch,0)+1
            
            for ch in char_count:
                if ch not in max_count: max_count[ch]=0
                max_count[ch] = max(max_count[ch], char_count[ch])
        
        print(max_count)
        
        res = []
        for string in A:
            char_count = {}
            for ch in string:
                char_count[ch] = char_count.get(ch,0)+1

            uni = True
            for key in max_count:
                if key not in char_count or max_count[key]>char_count[key]:
                    uni = False
                    break
            
            if uni:
                res.append(string)
        
        return res
            
        


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
                
        b_union = {}
        for b in B:
            chars = {}
            for c in b:
                chars[c] = chars.get(c,0) + 1
            for c in chars:
                b_union[c] = max(b_union.get(c,0), chars[c])
        
        res = []
        for a in A:
            chars = {}
            for c in a:
                chars[c] = chars.get(c,0) + 1
            isUniversal = True
            for c in b_union:
                if not c in chars or b_union[c]>chars[c]:
                    isUniversal = False
                    break
            if isUniversal:
                res.append(a)
        return res

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        d=defaultdict(int)
        for i in B:
            for j in set(i):
                d[j]=max(i.count(j),d[j])
        l=[]
        for i in A:
            if(all(d[j]<=i.count(j) for j in list(d.keys()))):
                l.append(i)
        return l
            


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        if not B:
            return A
        
        
        mapB = [0]*26
        B = list(set(B))
        for b in B:
            if not b:
                continue
            counter = collections.Counter(b)
            for k in b:
                index = ord(k) - ord('a')
                if counter[k] > mapB[index]:
                    mapB[index] = counter[k]
        
        print(mapB)
        res = []
        for a in A:
            temp = mapB[:] #deep copy
            for c in a:
                i = ord(c) - ord('a')
                if temp[i] > 0:
                    temp[i] -=1
            if sum(temp) == 0:
                res.append(a)
                
        return res
                
                
                    
                    


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        uni = []
        ## 1-  create a cover for B by creating a histogram of items
        # for example if B = [\"cb\",\"aae\",\"ccc\",\"ab\",\"adc\"]
        # its cover will be a histogram B_hist = {'c': 3, 'b': 1, 'a': 2, 'e': 1, 'd': 1}
        B_set = set(''.join(B))
        B_hist = {b_i: [max([b.count(b_i) for b in B]), -1] for b_i in B_set}
        
        ## 2- search for the universals using B_hist
        for a in A:
            occurances_b = 0
            for b_i in B_set:
                occurances_b_i = 0
                stop = False
                B_hist[b_i][1] = -1
                for j in range(B_hist[b_i][0]):
                    B_hist[b_i][1] = a.find(b_i, B_hist[b_i][1]+1)
                    if B_hist[b_i][1] == -1:
                        stop = True
                        break
                    else:
                        occurances_b_i += 1
                if stop == True:
                    break   
                if occurances_b_i == B_hist[b_i][0]:
                    occurances_b += 1   
            #print(a, occurances_b)
            if occurances_b == len(B_set):
                uni.append(a)
                    
        return uni

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        max_count = {}
        for string in B:
            char_count = {}
            for ch in string:
                char_count[ch] = char_count.get(ch,0)+1
            
            for ch in char_count:
                if ch not in max_count: max_count[ch]=0
                max_count[ch] = max(max_count[ch], char_count[ch])
        
        print(max_count)
        
        res = []
        for string in A:
            char_count = {}
            for ch in string:
                char_count[ch] = char_count.get(ch,0)+1

            ctr = 0
            for key in max_count:
                if key in char_count and max_count[key]<=char_count[key]:
                    ctr+=1
                else: break
            
            if ctr == len(max_count):
                res.append(string)
        
        return res
            
        


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        ans=[]
        word={}
        for i in B:
            for j in i:
                if(j not in word):
                    word[j]=i.count(j)
                else:
                    if(i.count(j)>word[j]):
                        word[j]=i.count(j)
                        
        for i in A:
            x=0
            for k in word:
                if(word[k]>i.count(k)):
                    x=1
                    break;
                
            if(x!=1):
                ans.append(i)
            
        return ans

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        max_count = {}
        for string in B:
            char_count = {}
            for ch in string:
                char_count[ch] = char_count.get(ch,0)+1
            
            for ch in char_count:
                if ch not in max_count: max_count[ch]=0
                max_count[ch] = max(max_count[ch], char_count[ch])
        
        print(max_count)
        
        res = []
        for string in A:
            char_count = {}
            for ch in string:
                char_count[ch] = char_count.get(ch,0)+1

            ctr = 0
            for key in max_count:
                if key in char_count and max_count[key]<=char_count[key]:
                    ctr+=1
            
            if ctr == len(max_count):
                res.append(string)
        
        return res
            
        


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        ans = []
        wordCountA = [ self.genWordCount(word) for word in A]
        wordCountB = [ self.genWordCount(word) for word in B]
        reducedWordB = {}
        for wordDict in wordCountB:
            for key, val in wordDict.items():
                reducedWordB[key] = max(reducedWordB[key], val) if key in reducedWordB else val

        for i in range(len(A)):
            if self.isSubset(wordCountA[i], reducedWordB):
                ans.append(A[i])

        return ans
    
    def genWordCount(self, word):
        wordCount = {}
        for c in word:
            if c in wordCount:
                wordCount[c] += 1
            else:
                wordCount[c] = 1
        return wordCount
    
    def isSubset(self, dictA, dictB):
        for key, val in dictB.items():
            if key not in dictA or dictA[key] < val:
                return False
        return True

from collections import defaultdict
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        ch2cnt = defaultdict(int)
        for b in B:
            tmp_cnt = defaultdict(int)
            for ch in b:
                tmp_cnt[ch] += 1
            for k, v in tmp_cnt.items():
                ch2cnt[k] = max(ch2cnt[k], v)
        res = []
        for a in A:
            tmp_dict = dict(ch2cnt)
            for ch in a:
                if ch in tmp_dict:
                    tmp_dict[ch] -= 1
                    if tmp_dict[ch] == 0:
                        tmp_dict.pop(ch)
            if len(tmp_dict) == 0:
                res.append(a)
        return res 

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        \"\"\"
        . create set for each B
        . merge all into one big set, saving number of most entries for each char
        
        . for each A,
        .. in the copy of setB, decrement and then delete char 
        .. if set becomed empty, add a to results 
        
        .. reset copy of setB
        
        
        \"\"\"
        setB = {}
        
        temp = {}
        for b in B:
            for c in b:
                temp[c] = temp.get(c, 0) + 1
            for (k, v) in temp.items():
                setB[k] = max(setB.get(k, 0), v)
            temp.clear()
        
        res = []
        keys = len(setB.keys())
        for a in A:
            temp = setB.copy()
            tempK = keys
            for c in a:
                if c in temp:
                    temp[c] -= 1
                    if temp[c] == 0:
                        # temp.pop(c)
                        tempK -= 1
                        if tempK == 0:
                            res.append(a)
                    
                        
        return res
            
        

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        universe = defaultdict(int)
        for b in B:
            bCount = defaultdict(int)
            for letter in b:
                bCount[letter] += 1
            for key in bCount:
                universe[key] = max(universe[key],bCount[key])
        
        # print(universe)
        
        result = []
        for a in A:
            aCount = defaultdict(int)
            for letter in a:
                aCount[letter] += 1
            isUni = True
            for letter in universe:
                if universe[letter] > aCount[letter]:
                    isUni = False
                    break
                else:
                    pass
            if isUni:
                result.append(a)
                
        return result

from collections import Counter
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        minFreq = {}
        for word in B:
            freq = Counter(word)
            for key, value in list(freq.items()):
                if key in minFreq:
                    if value > minFreq[key]:
                        minFreq[key] = value
                else:
                    minFreq[key] = value
        ans = []
        for word in A:
            c = minFreq.copy()
            flag = True
            for i in range(len(word)):
                if word[i] in c:
                    c[word[i]] -= 1
            for value in list(c.values()):
                if value > 0:
                    flag = False
                    break
            if flag:
                ans.append(word)
        return ans


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        def get_b_map(words):
            res = collections.defaultdict(int)
            for word in words:
                temp_dict = collections.defaultdict(int)
                for char in word:
                    temp_dict[char] += 1
                    res[char] = max(res[char], temp_dict[char])
            return res
        
        b_map = get_b_map(B)
        
        def contains(word, b_map):
            same_freqs = 0
            temp_dict = collections.defaultdict(int)
            for char in word:
                if char not in b_map:
                    continue
                    
                temp_dict[char] += 1
                if temp_dict[char] == b_map[char]:
                    same_freqs += 1
            return same_freqs == len(b_map)
        
        res = []
        for word in A:
            if contains(word, b_map):
                res.append(word)
        return res

from collections import Counter
class Solution:
    def wordSubsets(self, A, B):
        \"\"\"
        :type A: List[str]
        :type B: List[str]
        :rtype: List[str]
        \"\"\"
        wordsInBCounts = Counter()
        for wordB in B:
            counts = Counter(wordB)
            for (key,value) in counts.items():
                if wordsInBCounts[key] < value:
                    wordsInBCounts[key] = value        
        words = []        
        for wordA in A:
            stringALetterCounts = Counter(wordA)
            universal = True
            for (key,value) in wordsInBCounts.items():
                if value > stringALetterCounts[key]:
                    universal = False
                    break
            if universal:
                words.append(wordA)
        return words

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        d={}
        for e in B:
            tmp={}
            for c in e:
                if c not in tmp:
                    tmp.update({c:1})
                else:
                    tmp[c]+=1
            if (not d) or (not tmp):
                d.update(tmp)
            else:
                for k,v in list(tmp.items()):
                    if k in d:
                        if v>d[k]:
                            d[k]=v
                    else:
                        d.update({k:v})
        #print(d)
        
        if not d:
            return A
        
        ans=[]
        for a in A:
            tmp={}
            f=True
            for e in a:
                if e not in tmp:
                    tmp.update({e:1})
                else:
                    tmp[e]+=1
            for k,v in list(d.items()):
                if k in tmp:
                    if v<=tmp[k]:
                        pass
                    else:
                        f=False
                        break
                else:
                    f=False
                    break
            if f:
                ans.append(a)
        
        return ans
                    


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        s = set(A)
        letters_required = {}
        for b in B:
            for c in b:
                count = b.count(c)
                if c not in letters_required or count > letters_required[c]:
                    letters_required[c] = count
        
        for a in A:
            for lr in letters_required:
                if a.count(lr) < letters_required[lr]:
                    s.remove(a)
                    break
        
        return list(s)

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        bLets = collections.Counter()
        for w in B:
            for l, cnt in collections.Counter(w).items():
                if cnt > bLets[l]:
                    bLets[l] = cnt
        bTotal = sum(bLets.values())
        bLets = bLets.most_common()
        result = []
        aLets = collections.Counter()
        for w in A:
            if len(w) >= bTotal:
                aLets.update(w)
                for l, cnt in bLets:
                    if cnt > aLets[l]:
                        break
                else:
                    result.append(w)
                aLets.clear()
        return result

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        def getFrequency(s):
            d ={}
            for l in s:
                d[l]=d.get(l,0)+1
            return d
        main={}
        
        for b in B:
            f = getFrequency(b)
            for k in f.keys():
                main[k]=max(main.get(k,0),f[k])
        
        out=[]
        for a in A:
            
            leto = getFrequency(a)
            cont = False
            for k in main.keys():
                if leto.get(k,0) < main[k]:
                    cont=True
                    break
                    
            if not cont:
                out.append(a)
                
        return out

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        dctB = {}
        for word in B:
            dct = {}
            for ch in word:
                cnt = dct.get(ch)
                dct[ch] = 1 if not cnt else dct[ch] + 1
            for key in dct:
                cnt = dctB.get(key)
                dctB[key] = dct[key] if not cnt else max(cnt, dct[key])

        res = []
        for word in A:
            dct = {}
            univ = True
            for ch in word:
                cnt = dct.get(ch)
                dct[ch] = 1 if not cnt else dct[ch] + 1
            for key in dctB:
                if not dct.get(key) or dct[key] < dctB[key]:
                    univ = False
                    break
            if univ:
                res.append(word)
        return res

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        dic = {}
        res = []
        for b in B:
            for char in b:
                dic[char] = max(dic.get(char, 0), b.count(char))
        for a in A:
            if all(a.count(k) >= dic[k] for k in dic):
                res.append(a)
        return res
                
              
#https://leetcode.com/problems/word-subsets/discuss/659164/Python-90-with-comments-and-explanation


def createHist(word):
    hist = {}
    for c in word:
        if c in list(hist.keys()):
            hist[c] += 1
        else:
            hist[c] = 1
    return hist


def isSubset(word1, word2Hist):
    word1Hist = createHist(word1)
    for c in list(word2Hist.keys()):
        if c in list(word1Hist.keys()):
            word1Occur = word1Hist[c]
            word2Occur = word2Hist[c]
            if word2Occur > word1Occur:
                return False
        else:
            return False
    return True
        
def isUniversal(word, bHist):
    if isSubset(word, bHist) == False:
        return False
    return True
    
def createMaxHistogram(arr):
    hist = {}
    for word in arr:
        wordHist = createHist(word)
        for key in list(wordHist.keys()):
            if key in list(hist.keys()):
                hist[key] = max(hist[key], wordHist[key])
            else:
                hist[key] = wordHist[key]
    return hist
    
    
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        res = []
        bHist = createMaxHistogram(B)
        for word in A:
            if isUniversal(word, bHist):
                res.append(word)
        return res


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        d = collections.defaultdict(int)
        for b in B:
            b = collections.Counter(b)
            for x in b:
                if b[x] > d[x]:
                    d[x] += b[x] - d[x]
        uni = []
        for a in A:
            c = collections.Counter(a)
            for i, n in list(d.items()):
                if i not in c or c[i] < n:
                    break
            else:
                uni.append(a)
        return uni


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        def is_subset(b_dict, a_dict):
            for k in b_dict:
                if k not in a_dict or a_dict[k] < b_dict[k]:
                    return False
                
            return True 
        
        def get_dict(b):
            counts = {}
            for ch in b:
                counts[ch] = counts.get(ch, 0) + 1
            return counts
        
        b_dicts = [get_dict(b) for b in B]
        max_b_dict = {}
        
        for b_dict in b_dicts:
            for key in b_dict:
                max_b_dict[key] = max(max_b_dict.get(key, 0), b_dict[key])

        out = []
        
        for a in A:
            a_dict = get_dict(a)
            
            if is_subset(max_b_dict, a_dict):
                out.append(a)
                
        return out 
                


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        d = defaultdict(lambda:0)
        for b in B:
            temp = defaultdict(lambda:0)
            for i in b:
                temp[i]+=1
            for k, v in list(temp.items()):
                d[k] = max(v, d[k])
        
        # print(d)
        output = []
        for a in A:
            temp = defaultdict(lambda:0)
            for i in a:
                temp[i]+=1
            # print(temp)
            add = True
            for k , v in list(d.items()):
                if k not in temp or v > temp[k]:
                    add = False
                    break
            if add:
                output.append(a)
        return output


from math import floor
from math import ceil
from math import sqrt
from collections import deque
import numpy
from _collections import deque
#from _ast import Num # LC doesn't like this
from heapq import *
from typing import List
import random

MOD = int(1e9 + 7)
BASE = 256


def getCCnt(w):
    cnt = {}
    for c in w:
        if not c in cnt:
            cnt[c] = 0
        cnt[c] += 1
    return cnt


class Solution:

    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        minCnt = {}
        for w in B:
            cToCnt = getCCnt(w)
            for c, cnt in cToCnt.items():
                if not c in minCnt:
                    minCnt[c] = 0
                minCnt[c] = max(minCnt[c], cnt)
        ans = []
        for w in A:
            cToCnt = getCCnt(w)
            good = 1
            for c, cnt in minCnt.items():
                if not (c in cToCnt and cToCnt[c] >= minCnt[c]):
                    good = 0
                    break
            if good:
                ans.append(w)
        return ans

\"\"\"
sol = Solution()
A = [\"amazon\", \"apple\", \"facebook\", \"google\", \"leetcode\"]
B = [\"e\", \"o\"]
B = [\"l\", \"e\"]
B = [\"e\", \"oo\"]
B = [\"lo\", \"eo\"]
B = [\"ec\", \"oc\", \"ceo\"]
print(sol.wordSubsets(A, B))
\"\"\"

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:  
        dict2 = {}
        for i2 in B:
            dict3 = {}
            for l in i2:
                if l in dict3.keys():
                    dict3[l] += 1
                else:
                    dict3[l] = 1
                if l not in dict2.keys():
                    dict2[l] = 0
                if dict3[l] > dict2[l]:
                    dict2[l] = dict3[l]
        result = []
        for i in A:
            dict1 = {}
            is_subset =True
            for l1 in i:
                if l1 in dict1.keys():
                    dict1[l1] +=1
                else:
                    dict1[l1] = 1
            for key in dict2.keys():
                if key in dict1.keys():
                    if dict1[key]<dict2[key]:
                        is_subset = False
                else:
                    is_subset = False
            if is_subset:
                result.append(i)
        return result

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        s = set(A)
        d = {}
        for i in B:
            for j in i:
                count = i.count(j)
                if j not in d or count > d[j]:
                    d[j] = count

        for i in A:
            for j in d:
                if i.count(j) < d[j]:
                    s.remove(i)
                    break
        return list(s)

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        bLets = collections.Counter()
        for w in B:
            for l, cnt in collections.Counter(w).items():
                if cnt > bLets[l]:
                    bLets[l] = cnt
        bLets = bLets.most_common()
        result = []
        for w in A:
            aLets = collections.Counter(w)
            for l, cnt in bLets:
                if cnt > aLets[l]:
                    break
            else:
                result.append(w)
        return result

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        final = []
        D = {}
        for i in B :
            b_counter = collections.Counter(i)
            for j in b_counter:
                D[j] = max(b_counter[j], D.get(j,0))
        for i in A:
            flag = True
            w = collections.Counter(i)
            for d in D:
                if w.get(d) and w[d]>=D[d]:
                    pass
                else:
                    flag = False
                    break
            if flag : final.append(i)
        return final

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        ret = []
        
        bdict = dict()
        for word in B:
            temp = collections.Counter(word)
            for let, val in temp.items():
                if let not in bdict:
                    bdict[let] = val
                else:
                    bdict[let] = max(bdict[let], val)
            
            
            
        for item in A:
            tempdict = collections.Counter(item)
            failed = False
            for let, val in bdict.items():
                if let not in tempdict:
                    failed = True
                    break
                elif tempdict[let] < val:
                    failed = True
                    break

            if not failed:
                ret.append(item)

        return ret

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        B_dict = collections.defaultdict(int)
        
        for elem in B: 
            elem_dict = collections.Counter(elem)
            for item in elem_dict: 
                B_dict[item] = max(B_dict[item], elem_dict[item])
        
        output = []
        for elem in A:
            found = True
            elem_dict = collections.Counter(elem)
            for item in B_dict:
                if item not in elem_dict or elem_dict[item] < B_dict[item]:
                    found = False
                    break
            if found:
                output.append(elem)
        
        return output

from collections import Counter


class Solution:
    def parse_word(self, word):
        return Counter(word)

    def update_counter(self, orig, new):
        for c in new:
            orig[c] = max(new[c], orig[c])
        
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        min_universal = Counter()
        for b in B:
            bc = Counter(b)
            self.update_counter(min_universal, bc)

        universals = []
        for a in A:
            ac = Counter(a)
            is_universal = True
            for c in min_universal:
                if ac[c] < min_universal[c]:
                    is_universal = False
                    break
            if is_universal:
                universals.append(a)
        return universals
            
        


import collections
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        res = []
        bcount = collections.defaultdict(int)
        for s in B:
            counter = collections.Counter(s)
            for c in list(counter.keys()):
                if bcount[c] < counter[c]:
                    bcount[c] = counter[c]
        for s in A:
            counter = collections.Counter(s)
            flag = True
            for c in list(bcount.keys()):
                if not counter[c] >= bcount[c]:
                    flag = False
                    break
            if flag:
                res.append(s)
        return res
                  


from collections import Counter
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        bcounter = Counter()
        
        for b in B:
            bbc = Counter(b)
            for c in bbc:
                if c not in bcounter or bbc[c] > bcounter[c]:
                    bcounter[c] = bbc[c]
        
        ans = []
        for a in A:
            aac = Counter(a)
            uni = True
            for c in bcounter:
                if c not in aac or aac[c] < bcounter[c]:
                    uni = False
                    break
            if uni: ans.append(a)
        return ans
            


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        # Create Dictionary
        dictionary = dict()
        for i in range(len(B)):
            prev_dict = dict(dictionary)
            for j in range(len(B[i])):
                char = B[i][j]
                if char in dictionary:
                    dictionary[char] += 1
                else:
                    dictionary[char] = 1
                if char not in prev_dict:
                    prev_dict[char] = 0
                    
            for key, value in list(prev_dict.items()):
                if dictionary[key] - prev_dict[key] > prev_dict[key]:
                    dictionary[key] -= prev_dict[key]
                else:
                    dictionary[key] = prev_dict[key]
            
            
                
        answer = []
        for i in range(len(A)):
            # Reset Dictionary
            current_dict = dict(dictionary)
            # print(current_dict)
            # Manipulate Dictionary
            for j in range(len(A[i])):
                char_a = A[i][j]
                if char_a in current_dict:
                    current_dict[char_a] -= 1
            
            # Check if word passes
            include_word = True
            for key, value in list(current_dict.items()):
                if value > 0:
                    include_word = False
            
            if include_word:
                answer.append(A[i])
                
        return answer
                    
            


from collections import Counter
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        total = Counter()

        for word in B:
            counts = Counter(word)
            for ch, count in list(counts.items()):
                total[ch] = max(total[ch], count)

        result = []
        for word in A:
            counts = Counter(word)

            is_universal = True
            for ch, count in list(total.items()):
                if counts[ch] < count:
                    is_universal = False
                    break

            if is_universal:
                result.append(word)

        return result


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        #Time Complexity: O(A+B), where A and B is the total amount of letters in A and B respectively.
        #Space O(A.length + B).
        if not B:
            return A
        
        mapB = collections.defaultdict(int) #max required number of each letter of all words in B
        for b in B:
            counter = collections.Counter(b)
            for k in counter:
                mapB[k] = max(counter[k], mapB[k])
        
        
        res = []
        for a in A:
            countA = collections.Counter(a)
            if all(countA[ch] >= mapB[ch] for ch in mapB ):
                res.append(a)
            
            
        return res
                
                
                    
                    


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        um={}
        result=[]
        for b in B:
            for letter in b:
                if letter not in um:
                    um[letter]=b.count(letter)
                elif b.count(letter)>um[letter]:
                    um[letter]=b.count(letter)
        for a in A:
            boola= True
            for i,n in um.items():
                if (i not in a) or a.count(i)<n:
                    boola= False
                    break
            if boola:
                result.append(a)
        return result          

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        A_cnt, B_cnt = [], collections.defaultdict(int)
        for a in A:
            A_cnt += [collections.Counter(a)]
        for b in B:
            b_cnt = collections.Counter(b)
            for key in b_cnt:
                B_cnt[key] = max(B_cnt[key], b_cnt[key])
        
        ret = []
        for i, a in enumerate(A_cnt):
            valid = True
            for key in B_cnt:
                if a[key] < B_cnt[key]:
                    valid=False
                    break
            
            if valid:
                ret += [A[i]]
        
        return ret

from collections import Counter
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        # build maxCountB
        maxCountB = {}
        for w in B:
            c = Counter(w)
            for k, cnt in list(c.items()):
                maxCountB[k] = max(maxCountB.get(k, 0), cnt)
        
        res = []
        for w in A:
            c = Counter(w)
            isUniversal = True
            for k, cnt in list(maxCountB.items()):
                if k not in c or cnt > c[k]:
                    isUniversal = False
                    break
            if isUniversal:
                res.append(w)
                
        return res


from collections import defaultdict, Counter
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        rd = defaultdict(int)
        for c in map(Counter, B):
            for i in c:
                rd[i] = max(rd[i], c[i])
        
        # b = \"\".join([i * rd[i] for i in rd])
        
        cts = {i : Counter(i) for i in A}
        for i in rd:        
            rdi = rd[i]
            keep = {}
            for c in cts:
                if i in cts[c] and cts[c][i] >= rdi:
                    keep[c] = cts[c] 
            cts = keep        
        return cts        
                    
        
                
                
            
                


from collections import Counter
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        # let A be length of A and B be length of B
        # let N be length of longest word in A
        # let M be length of longest word in B
        
        # time: O(AN + BM)
        # space: O(AN + M)
        counts_A = [Counter(a) for a in A]
        word_B = Counter()
        for b in B:
            for k, v in Counter(b).items():
                if k not in word_B or word_B[k] < v:
                    word_B[k] = v
        
        
        # time: O(AM)
        # space: O(A)
        ans = []
        for i, a in enumerate(counts_A):
            ind = 1
            for letter in word_B.keys():
                if letter not in a or a[letter] < word_B[letter]:
                    ind = 0 
                    break
            if ind:
                ans.append(A[i])
        return ans

from collections import Counter
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        cnt = Counter()
        for word in B:
            wordcnt = Counter(word)
            for c in wordcnt:
                if cnt[c] < wordcnt[c]:
                    cnt[c] = wordcnt[c]
        ans = []
        for word in A:
            wordcnt = Counter(word)
            if all(wordcnt[c] >= cnt[c] for c in cnt):
                ans.append(word)
        return ans


from collections import defaultdict, Counter
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        rd = defaultdict(int)
        for c in map(Counter, B):
            for i in c:
                rd[i] = max(rd[i], c[i])
        
        # b = \"\".join([i * rd[i] for i in rd])
        
        cts = {i : Counter(i) for i in A}
        for i in rd:        
            rdi = rd[i]
            rm = set()
            for c in cts:
                if i not in cts[c] or cts[c][i] < rdi:
                    rm.add(c)
            for r in rm:
                cts.pop(r)
        return cts        
                    
        
                
                
            
                


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        ret = []
        
        bdict = dict()
        for word in B:
            temp = collections.Counter(word)
            for let, val in temp.items():
                if let not in bdict:
                    bdict[let] = val
                else:
                    bdict[let] = max(bdict[let], val)
            
        i = 0
        while i < len(A):
            tempdict = collections.Counter(A[i])
            failed = False
            for let, val in bdict.items():
                if let not in tempdict:
                    failed = True
                    break
                elif tempdict[let] < val:
                    failed = True
                    break

            if failed:
                del A[i]
            else:
                i = i + 1

        return A

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        bdict = dict()
        for word in B:
            temp = collections.Counter(word)
            for let, val in temp.items():
                if let not in bdict:
                    bdict[let] = val
                else:
                    bdict[let] = max(bdict[let], val)
            
        i = 0
        while i < len(A):
            tempdict = collections.Counter(A[i])
            failed = False
            for let, val in bdict.items():
                if let not in tempdict:
                    failed = True
                    break
                elif tempdict[let] < val:
                    failed = True
                    break

            if failed:
                del A[i]
            else:
                i = i + 1

        return A

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        s = set(A)
        letters_required = {}
        for i in B:
            for j in i:
                count = i.count(j)
                if j not in letters_required or count > letters_required[j]:
                    letters_required[j] = count

        for i in A:
            for j in letters_required:
                if i.count(j) < letters_required[j]:
                    s.remove(i)
                    break
        return list(s)


from collections import Counter
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        A = [(Counter(a), a) for a in A]
        B = [Counter(b) for b in B]
        
        # calculate universal requirements
        req = {}
        for cntr in B:
            for k,v in list(cntr.items()):
                req[k] = max(req.get(k, 0), v)
        
        # collect sols fulfilling requirements
        sol = [a for cntr, a in A if all(cntr.get(k, 0) >= v for k,v in list(req.items()))]
        return sol


class Solution:
    \"\"\"
    [\"amazon\",\"apple\",\"facebook\",\"google\",\"leetcode\"]
    [\"lo\",\"eo\"]
    Expected: [\"google\",\"leetcode\"]
        
    [\"amazon\",\"apple\",\"facebook\",\"google\",\"leetcode\"]
    [\"e\",\"o\"]
    Expected: [\"facebook\",\"google\",\"leetcode\"]
    
    [\"amazon\",\"apple\",\"facebook\",\"google\",\"leetcode\"]
    [\"e\",\"oo\"]
    [\"facebook\",\"google\"]
    \"\"\"
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        bchars = collections.defaultdict(int)
        for b in B:
            bcount = collections.Counter(b)
            for key in bcount:
                bchars[key] = max(bchars[key], bcount[key])
        result=[]
        for a in A:
            achars = collections.Counter(a)
            subset = True
            for c in bchars:
                if bchars[c] <= achars[c]:
                    continue
                else:
                    subset = False
                    
            if subset:
                result.append(a)
        return result

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        Acount = {word: collections.Counter(word) for word in A}
        Bcount = defaultdict(int)
        for b in B:
            b = collections.Counter(b)
            for k, v in b.items():
                Bcount[k] = max(Bcount[k], v)
        res = []
        for word in A:
            wCount = Acount[word]
            isWord = True
            for k, v in Bcount.items():
                if k in wCount and wCount[k] >= v:
                    continue
                else:
                    isWord = False
                    break
            if isWord:
                res.append(word)
        return res

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        # b_counts = [[0]*(ord('z')-ord('a')) for _ in len(B)]
        
        common_counter = defaultdict(int)
        for b_str in B:
            b_cnt = Counter(b_str)
            for b_let, b_let_cnt in b_cnt.items():
                common_counter[b_let] = max(common_counter[b_let], b_let_cnt)
                
        result = []
        for a_str in A:
            a_cnt = Counter(a_str)
            if all(a_cnt.get(c_let, 0) >= c_let_cnt for c_let, c_let_cnt in common_counter.items()):
                result.append(a_str)
        return result

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        d = {}
        for i in B:
            temp = Counter(i)
            for j in temp:
                d[j] = max(d.get(j,0),temp[j])
        
        ans = []
        for i in A:
            temp = Counter(i)
            flag = True
            for j in d:
                if(temp.get(j) and temp[j] >= d[j]):
                    pass
                else:
                    flag = False
                    break
            if flag:
                ans.append(i)
        return ans


import collections
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        B_count = collections.Counter()
        for ele in B:
            B_count |= collections.Counter(ele)
        res = []
        for ele in A:
            ele_count = collections.Counter(ele)
            for letter,count in list(B_count.items()):
                if ele_count[letter]<count:
                    break
            else:
                res.append(ele)
        return res
                
        
        
        


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        b_chars = defaultdict(int)
        for b in B:
            chars = Counter(b)
            for c in b:
                b_chars[c] = max(b_chars[c], chars[c])
        output = []
        for a in A:
            a_chars = Counter(a)
            if all(a_chars[c] >= b_chars[c] for c in b_chars):
                output.append(a)    
        return output

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        book = collections.defaultdict(int)
        for b in B:
            book2 = Counter(b)
            for bb in book2:
                book[bb] = max(book[bb], book2[bb]) 
        
        res = []
        for a in A:
            aa = Counter(a)
            if all(k in aa and aa[k] >= book[k] for k in book):
                res.append(a)
        return res
            


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        # b_counts = [[0]*(ord('z')-ord('a')) for _ in len(B)]
        
        b_counters = [Counter(b_str) for b_str in B]
        common_counter = defaultdict(int)
        for b_cnt in b_counters:
            for b_let, b_let_cnt in b_cnt.items():
                common_counter[b_let] = max(common_counter[b_let], b_let_cnt)
                
        result = []
        for a_str in A:
            a_cnt = Counter(a_str)
            if all(a_cnt.get(c_let, 0) >= c_let_cnt for c_let, c_let_cnt in common_counter.items()):
                result.append(a_str)
        return result

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        counter_b = Counter()
        
        for b in B:
            for key, freq in Counter(b).items():
                counter_b[key] = max(counter_b[key], freq)
            
        ans = []
        for a in A:
            counter_a = Counter(a)
            for key, freq in counter_b.items():
                if counter_a[key] < freq:
                    break
            else:
                ans.append(a)
        
        return ans

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        
        d, ret = {}, []
        
        for word in B:
            
            b = Counter(word)
            
            for key, val in list(b.items()):
                
                if key not in d:
                    d[key] = val
                else:
                    d[key] = max(d[key],  val)
                
        
        for cand in A:
            flag = True
            a = Counter(cand)
            
            for key, val in list(d.items()):
                
                if key not in a or val > a[key]:
                    
                    flag = False
            
            if flag:
                ret.append(cand)
        
        return ret
                
                
                


import collections as clc


class Solution:
    
    def subset(self, counter1: clc.Counter, counter2: clc.Counter) -> bool:
        return all(cnt1 <= counter2[char] for char, cnt1 in counter1.items())
    
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        max_b_counter = clc.Counter()
        for b in B:
            for char, cnt in clc.Counter(b).items():
                max_b_counter[char] = max(max_b_counter[char], cnt)
        ans = []
        for a in A:
            if self.subset(max_b_counter, clc.Counter(a)):
                ans.append(a)
        return ans

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        d = collections.Counter()
        
        for w in B:
            for c,n in collections.Counter(w).items():
                d[c] = max(n,d[c]) #max(2,1)
        res =[]
        for w in A:
            t = collections.Counter(w)
            if all(t[x]>=d[x] for x in d):
                res.append(w)
        return res

from collections import Counter


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        \"\"\"
        https://youtu.be/-IPzqZeVmr4?t=755
        \"\"\"
        result = []
        b_count = Counter()
        for b in B:
            for char, cnt in Counter(b).items():
                b_count[char] = max(b_count[char], cnt)

        for a in A:
            a_count = Counter(a)
            if all(a_count[char] >= b_count[char] for char in b_count):
                result.append(a)

        return result


from collections import Counter
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        res = []
        counter_b = Counter()
        for b in B:
            tmp = Counter(b)
            for t in tmp:
                counter_b[t] = max(counter_b[t], tmp[t])
        for a in A:
            count = Counter(a)
            invalid = False
            for c in counter_b:
                if count[c] < counter_b[c]:
                    invalid = True
            if not invalid:
                res.append(a)
        return res

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        max_b_counter = defaultdict(int)
        
        for word in B:
            word_counter = Counter(word)
            
            for char, counter in list(word_counter.items()):
                max_b_counter[char] = max(max_b_counter[char], word_counter[char])
        
        result = []
        
        for word in A:
            word_counter = Counter(word)
            
            if all([max_b_counter[char] <= word_counter[char] for char in max_b_counter]):
                result.append(word)
        
        return result



class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        s = set(A)
        letters_required = {}
        for i in B:
            for j in i:
                count = i.count(j)
                if j not in letters_required or count > letters_required[j]:
                    letters_required[j] = count

        for i in A:
            for j in letters_required:
                if i.count(j) < letters_required[j]:
                    s.remove(i)
                    break
        return list(s)
        # m = {}
        # for i in range(26):
        #     letter = chr(ord('a')+i)
        #     m[letter] = 0
        #     for w in B:
        #         ct_curr_l = 0
        #         for l in w:
        #             if l == letter:
        #                 ct_curr_l+=1
        #         m[letter] = max(m[letter],ct_curr_l)
        # res = []
        # for w in A:
        #     A_m = {}
        #     rt = True
        #     for l in w:
        #         if not l in A_m:
        #             A_m[l] = 0
        #         A_m[l]+=1
        #     for k in m:
        #         if m[k]>0 and ((k not in A_m) or (A_m[k]<m[k])):
        #             rt = False
        #     if rt == True:
        #         res.append(w)
        # return res
                
                
        
                
                
                


import collections
class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        #Time Complexity: O(A+B), where A and B is the total amount of letters in A and B respectively.
        #Space O(A.length + B.length).
        if not B:
            return A
        
        mapB = defaultdict(int) #max required number of each letter of all words in B
        for b in B:
            counter = Counter(b)
            for k in counter:
                mapB[k] = max(counter[k], mapB[k])
        
        res = []
        for a in A:
            countA = Counter(a)
            if all( [ countA[ch] >= mapB[ch] for ch in mapB ] ):
                res.append(a)     
            
        return res
                
                
                    
                    


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        b=collections.Counter(B[0])
        f=collections.defaultdict(int)
        for x in B:
            p=Counter(x)
            for k in list(p.keys()):
                if k in b:
                    b[k]=max(p[k],b[k])
                else:
                    b[k]=p[k]
        res=[]
        for word in A:
            word_counter=collections.Counter(word)
            add=True
            for i in b:
                if i not in word_counter or b[i]>word_counter[i]:
                    add=False
            if add:
                res.append(word)
        return res    
                    


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        counter = Counter()
        for b in B:
            cb = Counter(b)
            for ch in cb:
                counter[ch] = max(counter[ch], cb[ch])
        ans = []
        for a in A:
            ca = Counter(a) 
            if all(ca[ch] >= counter[ch] for ch in counter):
                ans.append(a)
        return ans        


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        a_counts = [Counter(a) for a in A]
        b_count = Counter()
        for b in B:
            for l, c in list(Counter(b).items()):
                b_count[l] = max(b_count[l], c)
        uni = []
        for i, ac in enumerate(a_counts):
            is_universal = True
            for l, c in list(b_count.items()):
                if ac[l] < c:
                    is_universal = False
                    break
            if is_universal:
                uni.append(A[i])
        return uni


import collections

class Solution:
  def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
    A = [(a,collections.Counter(a)) for a in A]
    newB = {}
    for b in B:
      for x, c in collections.Counter(b).items():
          newB[x] = c if x not in newB else max(newB[x], c)
      
    B = newB
    
    ans = []
    for a, counts in A:
      allMatch = True
      
      for x,c in B.items():
        if counts[x] < c:
          allMatch = False
          break
      
      if allMatch: ans.append(a)

    return ans

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        a_counter = [Counter(a) for a in A]
        b_counter = [Counter(b) for b in B]
        
        bc = {}
        for counter in b_counter:
            for b, frequency in counter.items():
                if b in bc:
                    bc[b] = max(bc[b], frequency)
                else:
                    bc[b] = frequency
                    
        def is_bc_in_ac(ai, ac):
            if len(bc) > len(A[ai]):
                return False

            for l, frequency in bc.items():
                if ac[l] < frequency:
                    return False
            return True
        
        res = []
        for ai, ac in enumerate(a_counter):
            if is_bc_in_ac(ai, ac):
                res.append(A[ai])
        return res

class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        maxcb = Counter()
        for b in B:
            for ch in (cb := Counter(b)):
                maxcb[ch] = max(maxcb[ch], cb[ch])
        ans = []
        for a in A:
            ca = Counter(a) 
            if all(ca[ch] >= maxcb[ch] for ch in maxcb):
                ans.append(a)
        return ans        


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        hashmap=defaultdict(int)
        for i in B:
            c=defaultdict(int)
            for p in i:
                c[p]+=1
            for n in c:
                hashmap[n]=max(hashmap[n],c[n])
        
        
        result=[]
        for i in A:
            count=defaultdict(int)
            for c in i:
                count[c]+=1
            flag=True
            for node in hashmap:
                if node not in count or count[node]<hashmap[node]:
                    flag=False
            if flag :
                result.append(i)
        return result       
                


class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        need = Counter()
        
        for word in B:
            word_count = Counter(word)
            for k, v in list(word_count.items()):
                need[k] = max(need[k], v)

        def is_subset(word):
            word_count = Counter(word)

            for c in need:
                word_count[c] -= need[c]
                if word_count[c] < 0:
                    return False
            
            return True
            
        res = []
        for word in A:
            if is_subset(word):
                res.append(word)
        
        return res



class Solution:
    def wordSubsets(self, A: List[str], B: List[str]) -> List[str]:
        max_counts = collections.defaultdict(int)
        for b in B:
            counts = collections.Counter(b)
            for char, count in list(counts.items()):
                max_counts[char] = max(max_counts[char], count)
                
        universals = []
        for a in A:
            counts = collections.Counter(a)
            for char, max_count in list(max_counts.items()):
                if counts[char] < max_count:
                    break
            else:
                universals.append(a)
                
        return universals