LeetCode 题解系列(1371):每个元音包含偶数次的最长子字符串

题目描述:

给你一个字符串 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. 5 个字母的出现奇偶次数可以用一个长度为 5 的二进制数字来表示。
  2. 5 个字母所有出现的情况可以用一个 32 长度的数组来表示。代表的就是当前数字上次出现的位置,初始都是-1。
  3. 遍历每个字符,将对应位置进行异或,代表改变当前为出现的奇偶次数,如果这个数字对应数组之前出现过,则证明子串[0,i]与字串[0,j]对应的状态数字相同,那么[i+1..j]的状态一定是 0,代表偶数出现的都抵消了。
  4. 每次出现偶数次,都进行更新当前代表的长度差,统计最大长度差。

时间复杂度: O(N); 辅助空间复杂度: O(N)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 前缀和
class Solution {
public int findTheLongestSubstring(String s) {
int n = s.length();
// 5个字母的奇偶性共有2^5=32个种可能
int[] pos = new int[1 << 5];
// 全部填充为-1,代表没有出现过
Arrays.fill(pos, -1);
int ans = 0;
int status = 0;
pos[0] = 0;
// 维护元音字母出现的次数改作维护元音字母出现次数的奇偶性
for (int i = 0; i < n; i++) {
char ch = s.charAt(i);
// 改变对应数字的奇偶性
if (ch == 'a') {
status ^= (1 << 0);
} else if (ch == 'e') {
status ^= (1 << 1);
} else if (ch == 'i') {
status ^= (1 << 2);
} else if (ch == 'o') {
status ^= (1 << 3);
} else if (ch == 'u') {
status ^= (1 << 4);
}
// 如果子串[0,i]与字串[0,j]对应的状态数字相同,那么[i+1..j]的状态一定是 0,代表偶数出现的都抵消了
if (pos[status] >= 0) {
ans = Math.max(ans, i + 1 - pos[status]);
} else {
pos[status] = i + 1;
}
}
return ans;
}
}

LeetCode 题解系列(1371):每个元音包含偶数次的最长子字符串
http://example.com/2020/07/11/D-DataStructureAndAlgorithm/D-LeetCode/1371-FindTheLongestSubstring/
作者
ChenXi
发布于
2020年7月11日
许可协议