1371. 每个元音包含偶数次的最长子字符串
摘要
Title: 1371. 每个元音包含偶数次的最长子字符串
Tag: 前缀和、状态压缩、哈希表
Memory Limit: 64 MB
Time Limit: 1000 ms
Powered by:NEFU AB-IN
1371. 每个元音包含偶数次的最长子字符串
-
题意
给你一个字符串 s ,请你返回满足以下条件的最长子字符串的长度:每个元音字母,即 ‘a’,‘e’,‘i’,‘o’,‘u’ ,在子字符串中都恰好出现了偶数次。
-
思路
- 遇到奇偶个数校验,想到:XOR
- 遇到有限的参数(小于20个)表状态, 想到:状态压缩
- 遇到求最长的连续子串使得和为k想到:前缀和 + 哈希表记录第一次出现某一状态的位置
思路
- 利用异或,将奇偶型转换为01问题,奇变偶,偶变奇,就是将当前状态异或1即可
- 利用状态压缩,将五个状态压缩成一个二进制表示,如01010,再转换为十进制存起来,这样就可以针对某一位进行异或
- 利用前缀和去求某一区间的状态,也就是当s[i]和s[j]状态相同时,s[j + 1, i]就是符合条件的
- 利用哈希表去求第一次某状态出现的下标
此题非常经典,具体细节见代码注释
-
代码
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
37
38
39
40
41
42
43
44
45
46
47// ---------------------
typedef pair<int, int> PII;
// #undef N
// const int N = 1e5 + 10;
static int IOS = []() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
return 0;
}();
class Solution
{
public:
int findTheLongestSubstring(string s)
{
vector<int> st(32, -INT_MAX);
// 一共 2^5 = 32种状态,初始化为负无穷,值为该状态最早的下标
// 二进制 00001 代表 1,代表u为奇数,其他为偶数
st[0] = -1; // 记录该下标的前一个,因为要进行前缀和操作
string p = "aeiou";
int state = 0; // 一开始都是偶数,即 00000
int ans = 0;
for (int i = 0; i < SZ(s); ++i)
{
int k = p.find(s[i]);
if (k != -1)
state ^= (1 << k); // state 的第k位异或1,某一元音的奇偶性就变了
if (st[state] == -INT_MAX)
// 说明还没更新过最小下标
st[state] = i;
else
ans = max(ans, i - st[state]);
// [j + 1, i] 即 i - (j + 1) + 1 即 i - j
}
return ans;
}
};
// ---------------------