【Leetcode刷题】每个元音包含偶数次的最长子字符串

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))

原文地址:https://www.cnblogs.com/luozx207/p/12924822.html