题目
给你一个字符串 s ,请你返回满足以下条件的最长子字符串的长度:
每个元音字母,即 ‘a’,‘e’,‘i’,‘o’,‘u’ ,在子字符串中都恰好出现了偶数次。
示例1
输入:s = "eleetminicoworoep"
输出:13
解释:最长子字符串是 "leetminicowor" ,它包含 e,i,o 各 2 个,以及 0 个 a,u 。
示例2
输入:s = "leetcodeisgreat"
输出:5
解释:最长子字符串是 "leetc" ,其中包含 2 个 e 。
示例3
输入:s = "bcbcbc"
输出:6
解释:这个示例中,字符串 "bcbcbc" 本身就是最长的,因为所有的元音 a,e,i,o,u 都出现了 0 次。
提示
1 <= s.length <= 5 x 10^5
s 只包含小写英文字母。
题解
一开始最容易想到的就是暴力枚举法,我用暴力枚举写了一下,结果显然是超时。
之后看了官方题解和一些大神们的解答,发现这道题可以用状态压缩+前缀和+哈希表来解决。
前缀和
前缀是指[0, x]
(从0开始的子串),用前缀和来表示子串区间[i, j]
,可以将两个变量化简为一个变量:
[i, j] = [0, j] - [0, i - 1]
[0, j]
和 [0, i - 1]
都可以用[0, x]
表示。
现在我们关心的是子串中元音字母出现的奇偶情况,而不是元音字母出现的次数,因此我们用状态压缩来表示每个元音字母出现的奇偶情况。
状态压缩
遇到有限的参数(小于20个)表状态, 想到状态压缩。
这里是将元音字母的出现次数做状态压缩,元音字母出现偶数次记为0,出现奇数次记为1。然后用二进制表示每个字母出现的奇偶次。比如在asaus
这个字符串中,a出现2次(偶数),u出现1次(奇数),其他元音字母都出现0次(偶数),那么它对应的状态就是10000
(uoiea),十进制数就是16。
因此,设置一个变量pattern表示当前的状态,pattern的取值范围就是0~31(00000~11111)
。
那如何计算pattern呢?首先设置一个hash表,将元音字母用对应的二进制表示。这里将二进制转化为了十进制。直接用1<<n
也是可以的。