1915 Number of Wonderful Substrings
几点问题,
- 如何能想到要用 bit shift + exclusive or (XOR) 来解决问题?
Approach 1: Prefix + Hash + Bit
odd frequency of letter appear at most 1, 可以被分解为两个子问题:
- 求ending at char i的substring中,有多少个odd letter出现0次
- 求ending at char i的substring中,有多少个odd letter出现1次
描述状态
为了更好的描述state, 我们可以用:
- letter出现过odd次, bit为0
- letter出现过even次, bit为1
每当我们substring长大时,我们可以用flip k-th bit来作为状态转移方程来迭代,mask ^= (1 << k), 也就是说我们可以用一个10位的mask来表示当前的状态,比如:
a (1 << 0)
b (1 << 1)
c (1 << 2)
d (1 << 3)
e (1 << 4)
f (1 << 5)
g (1 << 6)
h (1 << 7)
i (1 << 8)
j (1 << 9)
假设s='', 初始值为0000000000, 你可以把它理解为每个char都只出现了偶数次. 每遇到一个新的char, 我们就flip对应的bit with XOR. 我们来做一下dry run, for substring 'acadac'
| substring | mask |
|---|---|
'' |
0 |
'a' |
1 |
'ac' |
101 |
'aca' |
100 |
'acad' |
1100 |
'acada' |
1101 |
'acadac' |
1001 |
接下来我们只需要维护一个hasmap作为我们的prefix即可,
{
0: 1,
1: 1,
101: 1,
100: 1,
1100: 1,
1101: 1,
1001: 1
}
子问题1: odd letter出现0次
我们只需要记录当前的mask, 看之前是否出现过,出现过几次就可以这个解的可能性. 维护一个frequency map即可
子问题2: odd letter出现1次
flip k-th bit, 然后看之前是否出现过,O(10)
Note
- Time Complexity: \(O(n)\)
- Space Complexity: \(O(n)\), worst case scenario 10个解
Code Implementation
from collections import defaultdict
class Solution:
def wonderfulSubstrings(self, word: str) -> int:
"""
case 1: odd freq出现0次
case 1: odd freq出现1次
表示state:
jihgfedcba
a --> 2^0 --> 1
b --> 2^1 --> 2
...
"""
# initialize a frequency map
freq = defaultdict(int)
freq[0] = 1
mask = res = 0
for char in word:
bit = ord(char) - ord('a')
# flip current char's bit to get flip mask
mask ^= (1 << bit)
# case 1: no letter appearing odd number of times
res += freq[mask]
freq[mask] += 1
# case 2: one letter appearing odd number of times
for odd_char in range(0,10):
curr = mask ^ (1 << odd_char)
if curr in freq:
res += freq[curr]
return res