Woodyiiiiiii / LeetCode

My private record of Leetcode solution

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Leetcode 1178. Number of Valid Words for Each Puzzle

Woodyiiiiiii opened this issue · comments

1178. Number of Valid Words for Each Puzzle

1178. Number of Valid Words for Each Puzzle

这道题我一开始发现每个word其字母排序、字母出现次数不重要,所以我的初步想法是:将每个word放入treeset中去重排序,再对每个puzzle也去重排序,然后对比,对于每个puzzle其是多少个word的前缀。(其实单个的word或者puzzle已经长度很小已经暗示了要对其中之一缓存)

接下来我一下子想到了字典树Trie。但问题是,是将word还是puzzle放入字典树里呢?按常理来说,应该放入words,这样遍历puzzles才能知道每个puzzle是多少个word的前缀,但这就违反了字典树的定义了——判断字符串是不是字典树里的前缀;反之,放入puzzles,遍历words,就算知道每个word是多少个puzzles的前缀,那该如何定位这几个puzzles呢,因为最后求的是puzzles对应的结果。

看了题解才知道,这需要放弃Trie,用状压bitmask来记录位置。我练习的bitmask类型题目还不多,所以还没这么敏感,遇到这类状态之间互不干扰且较小的题目可以用bitmask考虑。

正解:遍历words,状态压缩,然后用哈希表记录每个整数值和数量;然后遍历puzzles,同样对于每个puzzle状压得到对应的整数;

接下来是第二个难点(第一个是想到状压):如何通过puzzle对应的二进制数找到所以满足其子集的words呢?通过(sub-1)&mask不断向下遍历,然后通过记录的map找到个数。对于是否包含第一个字符,则加个判断即可。

时间复杂度:O( n * 2 ^ 7 + m * k) = O(n + mk)

class Solution {
    public List<Integer> findNumOfValidWords(String[] words, String[] puzzles) {
        Map<Integer, Integer> cntMap = new HashMap<>();
        for (String word : words) {
            int mask = 0;
            for (char c : word.toCharArray()) {
                mask |= 1 << (c - 'a');
            }
            cntMap.put(mask, cntMap.getOrDefault(mask, 0) + 1);
        }
        
        List<Integer> res = new ArrayList<>();
        for (String puzzle : puzzles) {
            char first = puzzle.charAt(0);
            int firstMask = 1 << (first - 'a');
            int mask = 0;
            for (char c : puzzle.toCharArray()) {
                mask |= 1 << (c - 'a');
            }
            int p = mask;
            int cnt = 0;
            while (p > 0) {
                if ((p & firstMask) > 0 && cntMap.containsKey(p)) {
                    cnt += cntMap.get(p);
                }
                p = (p - 1) & mask;
            }
            res.add(cnt);
        }
        return res;
    }
}
func findNumOfValidWords(words []string, puzzles []string) []int {
    // cache with bit mask
	wordsMap := make(map[int]int)
	for _, word := range words {
		mask := 0
		for _, ch := range word {
			mask |= 1 << (ch - 'a')
		}
		wordsMap[mask]++
	}
	
	res := make([]int, 0)
	for _, puzzle := range puzzles {
		mask := 0
		for _, ch := range puzzle {
			mask |= 1 << (ch - 'a')
		}
		subInt := mask
		firstC := puzzle[0]
		firstMask := 1 << (firstC - 'a')
		cnt := 0
		for ; subInt > 0; subInt = (subInt - 1) & mask {
			if subInt&firstMask > 0 {
				cnt += wordsMap[subInt]
			}
		}
		res = append(res, cnt)
	}
	return res
}