Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Leetcode 1178. Number of Valid Words for Each Puzzle #244

Open
Woodyiiiiiii opened this issue Apr 24, 2023 · 0 comments
Open

Leetcode 1178. Number of Valid Words for Each Puzzle #244

Woodyiiiiiii opened this issue Apr 24, 2023 · 0 comments

Comments

@Woodyiiiiiii
Copy link
Owner

Woodyiiiiiii commented Apr 24, 2023

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
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant