1371. 每个元音包含偶数次的最长子字符串题解
思路:
这一题我最开始能想到的思路就是使用hashMap(或者数组),但是发现每次需要检查每个字母个数真的太麻烦了,而且我所使用的方法是默认字符串是从0开始的而不是任意位置,所以我对题目的理解也存在问题。
为了解决以上两个问题,首先我们要求的是连续字符字串,所以我们能会想到前缀和算法,那么这一题也能采用这种思想。其次为了每次判断各个字符个数更方便(无需再嵌套循环)我们可以采用状态压缩的方式。整理一下思路:
由奇偶个数校验容易想到XOR->
然后由于元音字母只有5个可以联想到状态压缩 ->
由求最长的连续子串使得和为k可以想到前缀和算法->
值得注意的是:pos数组只记录第一次出现的相应状态的字符下标,为了区分是否该状态出现过,我们将数组中所有元素初始化为-1即可。
class Solution {
public int findTheLongestSubstring(String s)
int n = s.length();
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) {//>=0表示更新过
ans = Math.max(ans, i + 1 - pos[status]);
} else {
pos[status] = i + 1;
}
}
return ans;
}
}
还需要注意的是 pos[status] = i + 1 是不可以写成 pos[status] = i 的,这样会和上面的 pos[0] = 0 混淆,而且 pos[0] = 0 也是必须初始化的,因为要想把从头开始的并且满足条件的字符串也计算在内,就必须初始化pos[0] 为 - 1 + 1.
或者用map:
private static final String VOWELS = "aeiou";
public int findTheLongestSubstring(String s) {
Map<Integer, Integer> map = new HashMap<>();
int size = s.length();
int state = 0; // (00000)
int maxSize = 0;
map.putIfAbsent(0, -1);
for (int i = 0; i < size; i ++){
for (int k = 0; k < VOWELS.length(); k++){
if (s.charAt(i) == VOWELS.charAt(k)){
state ^= (1 << (k+1));
break;
}
}
if (map.containsKey(state)){
maxSize = Math.max(maxSize, i - map.get(state));
}
map.putIfAbsent(state, i);
}
return maxSize;
}