1371. 每个元音包含偶数次的最长子字符串
- 原题链接:
- 完成情况:
- 解题思路:
- 参考代码:
- _1371每个元音包含偶数次的最长子字符串
- 错误经验吸取
原题链接:
1371. 每个元音包含偶数次的最长子字符串
https://leetcode.cn/problems/find-the-longest-substring-containing-vowels-in-even-counts/description/
完成情况:
解题思路:
这段代码是用来解决一个特定的问题:找出给定字符串中最长的一个子串,使得该子串中的所有元音字母(‘a’, ‘e’, ‘i’, ‘o’, ‘u’)都出现了偶数次。
代码的主要思想基于状态压缩和前缀和的概念,具体解释如下:
-
状态压缩:使用一个二进制数来表示5个元音字母出现次数的奇偶性。例如,状态
01010
表示’a’和’o’出现了奇数次,而’e’, ‘i’, 和’u’出现了偶数次。因为只有5个元音字符,状态总数为2的5次方(1 << 5
)即32种状态。 -
数组
position
初始化:创建一个长度为32的数组position
,用来记录每种状态第一次出现的位置索引。初始值设为-1,因为一开始任何状态都未曾出现。 -
遍历字符串:遍历整个字符串,使用局部变量
status
来跟踪当前的状态。对每个字符,检查它是否是元音字母,并更新状态。- 更新状态使用异或运算
^
(XOR),这个操作可以翻转特定位的值。例如,如果’a’字符出现一次,则status
的第0位翻转一次(status ^= (1 << 0)
),出现两次则再翻转回来,保证如果出现偶数次则该位为0。
- 更新状态使用异或运算
-
计算最长子串:在遍历过程中,每次更新
status
后,检查这个状态是否已经出现过。- 如果出现过(
position[status] >= 0
),说明从之前的位置到当前位置,所有元音字母出现了偶数次,因此使用Math.max
来尝试更新结果result
。 - 如果这个状态是第一次出现,记录它的位置(
position[status] = i + 1
)。这里i + 1
是因为数组的初始位置(position[0]
)被预设为0来表示开始前的状态。
- 如果出现过(
遍历完成后,变量result
包含了满足条件的最长子串的长度。
参考代码:
_1371每个元音包含偶数次的最长子字符串
package leetcode板块;
import java.util.Arrays;
public class _1371每个元音包含偶数次的最长子字符串 {
/**
*
* @param s
* @return
*/
public int findTheLongestSubstring(String s) {
/*
这样我们就可以将 555 个元音字母出现次数的奇偶性压缩到了一个二进制数中,且连续对应了二进制数的 [(00000)2,(11111)2][(00000)_2,(11111)_2][(00000) 2 ,(11111) 2 ] 的范围,
转成十进制数即 [0,31][0,31][0,31]。因此我们也不再需要使用哈希表,直接用一个长度为 323232 的数组来存储对应状态出现的最早位置即可。
*/
int n = s.length();
int position [] = new int[1 << 5];
Arrays.fill(position,-1);
int result = 0,status = 0;
//position[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);
}
if (position[status] >= 0){ //全部都为偶数
result = Math.max(result,i + 1 - position[status]);
}else {
position[status] = i + 1;
}
}
return result;
}
}