|
| 1 | +# Time: O(n*l + m*L), m is the number of puzzles, L is the length of puzzles |
| 2 | +# , n is the number of words, l is the max length of words |
| 3 | +# Space: O(L!) |
| 4 | + |
| 5 | +class Solution(object): |
| 6 | + def findNumOfValidWords(self, words, puzzles): |
| 7 | + """ |
| 8 | + :type words: List[str] |
| 9 | + :type puzzles: List[str] |
| 10 | + :rtype: List[int] |
| 11 | + """ |
| 12 | + L = 7 |
| 13 | + def search(node, puzzle, start, first, met_first): |
| 14 | + result = 0 |
| 15 | + if "_end" in node and met_first: |
| 16 | + result += node["_end"]; |
| 17 | + for i in xrange(start, len(puzzle)): |
| 18 | + if puzzle[i] not in node: |
| 19 | + continue |
| 20 | + result += search(node[puzzle[i]], puzzle, i+1, |
| 21 | + first, met_first or (puzzle[i] == first)) |
| 22 | + return result |
| 23 | + |
| 24 | + _trie = lambda: collections.defaultdict(_trie) |
| 25 | + trie = _trie() |
| 26 | + for word in words: |
| 27 | + count = set(word) |
| 28 | + if len(count) > L: |
| 29 | + continue |
| 30 | + word = sorted(count) |
| 31 | + end = reduce(dict.__getitem__, word, trie) |
| 32 | + end["_end"] = end["_end"]+1 if "_end" in end else 1 |
| 33 | + result = [] |
| 34 | + for puzzle in puzzles: |
| 35 | + first = puzzle[0] |
| 36 | + result.append(search(trie, sorted(puzzle), 0, first, False)) |
| 37 | + return result |
| 38 | + |
| 39 | + |
| 40 | +# Time: O(m*2^(L-1) + n*(l+m)), m is the number of puzzles, L is the length of puzzles |
| 41 | +# , n is the number of words, l is the max length of words |
| 42 | +# Space: O(m*2^(L-1)) |
| 43 | +import collections |
| 44 | + |
| 45 | + |
| 46 | +class Solution2(object): |
| 47 | + def findNumOfValidWords(self, words, puzzles): |
| 48 | + """ |
| 49 | + :type words: List[str] |
| 50 | + :type puzzles: List[str] |
| 51 | + :rtype: List[int] |
| 52 | + """ |
| 53 | + L = 7 |
| 54 | + lookup = collections.defaultdict(list) |
| 55 | + for i in xrange(len(puzzles)): |
| 56 | + bits = [] |
| 57 | + base = 1 << (ord(puzzles[i][0])-ord('a')) |
| 58 | + for j in xrange(1, L): |
| 59 | + bits.append(ord(puzzles[i][j])-ord('a')) |
| 60 | + for k in xrange(2**len(bits)): |
| 61 | + bitset = base |
| 62 | + for j in xrange(len(bits)): |
| 63 | + if k & (1<<j): |
| 64 | + bitset |= 1<<bits[j] |
| 65 | + lookup[bitset].append(i) |
| 66 | + result = [0]*len(puzzles) |
| 67 | + for word in words: |
| 68 | + bitset = 0 |
| 69 | + for c in word: |
| 70 | + bitset |= 1<<(ord(c)-ord('a')) |
| 71 | + if bitset not in lookup: |
| 72 | + continue |
| 73 | + for i in lookup[bitset]: |
| 74 | + result[i] += 1 |
| 75 | + return result |
0 commit comments