题目
思路
实在没思路,使用滑动窗口,地太溜。只能使用暴力法了。
- 暴力法:从每一个字符串开始,都有可能存在最长子串。所以从每个字符串开始,遍历它之后的字符串。
代码
class Solution {
public int findTheLongestSubstring(String s) {
int len = s.length();
int max = 0;
// 默认都是偶数,false
boolean[] counts = {false, false, false, false, false};
for(int i=0; i<len; i++){
// 对于每一个字母打头的子字符串,都计算一下,它到末尾的偶数和
int right = i;
for(int j=0; j<5; j++) {
if(counts[j]) counts[j]=false;
}
while(right < len){
char ch = s.charAt(right);
switch(ch){
case 'a': counts[0] = counts[0]?false:true;break;
case 'e': counts[1] = counts[1]?false:true;break;
case 'i': counts[2] = counts[2]?false:true;break;
case 'o': counts[3] = counts[3]?false:true;break;
case 'u': counts[4] = counts[4]?false:true;break;
}
boolean flag = true;
for(boolean bool:counts){
if(bool) {
flag = false;
break;
}
}
// 如果都是偶数次,则记录最大长度
if(flag) {
max = Math.max(right-i+1, max);
if(max == len-i) return max;
}
right++;
}
}
return max;
}
}
题解
使用前缀和、哈希化、还有异或,还有状态值,状态值转换成二进制。这道题太牛逼了!!!
class Solution {
public int findTheLongestSubstring(String s) {
int n = s.length();
// ‘00000’ 和 '11111' 二进制范围为 0-31
int[] pos = new int[1 << 5];
Arrays.fill(pos, -1);
int ans = 0, 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);
}
// 这里的原理是,奇数 - 奇数 = 偶数; 偶数 - 偶数 = 偶数!!!
// 如果前一个位置是奇数状态,下一次又是同样的奇数状态的时候,它会包含了第一个该奇数状态
// 之前的所有处理结果。所以在第一个奇数状态和第二个奇数状态之间是偶数状态
if (pos[status] >= 0) {
// 这里的 i+1
ans = Math.max(ans, i + 1 - pos[status]);
} else {
// 这里记录第一次出现该状态时候的位置
// 这里的 i+1都是不能省却的,因为 pos[status] = 0的
pos[status] = i + 1;
}
}
return ans;
}
}