https://leetcode-cn.com/problems/find-the-longest-substring-containing-vowels-in-even-counts/
这题真的太难了,看答案都想了两个小时,我建议调整难度为困难不过分吧?orz
class Solution:
def findTheLongestSubstring(self, s: str) -> int:
# 前缀和+状态压缩
# 记录s[:i]中五个元音的奇偶数量pattern,如果s[:j]的pattern与s[:i]相同,则s[i+1:j]的元音数量都是偶数
# 五个元音,每个都有奇偶两种状态,因此pattern的数量为2^5=32
# 记录每个pattern最早出现的位置(因为需要求最长子串)
# 如果pattern没有出现过,则初始化为None
memo = [None for _ in range(32)]
# 还没开始遍历s时,所有元音都没有出现,因此是[00000]=0,并且此时索引为-1,即第一个字符之前的位置
memo[0] = -1
# 遍历过程中元音的pattern
pattern = 0
# 符合要求子字符串的最大长度
max_len = 0
for i in range(len(s)):
# 做位运算求出当前pattern
if s[i] == 'a':
pattern ^= (1 << 0)
elif s[i] == 'e':
pattern ^= (1 << 1)
elif s[i] == 'i':
pattern ^= (1 << 2)
elif s[i] == 'o':
pattern ^= (1 << 3)
elif s[i] == 'u':
pattern ^= (1 << 4)
if memo[pattern] is not None:
# 以s[i]结尾的符合要求的最长子字符串
# 为什么是这样,一步步写出"leetcodeo"遍历过程pattern和max_len的变化就懂了
cur_len = i - memo[pattern]
max_len = max(cur_len, max_len)
else:
# 为什么这里只更新memo不求max_len呢?
# 因为当memo[pattern] is None,说明这个pattern以前没有出现过
# 说明s[i]必然是一个元音,因为pattern被更新了
# 并且不存在s[j:i]符合条件,s[i]这个子字符串也不符合条件,因为当前元音出现了一次
# 因此这种情况下cur_len=0,不需要更新max_len
memo[pattern] = i
return max_len
时间复杂度:O(n)
空间复杂度:O(len(memo))