给你字符串 s 和整数 k 。
请返回字符串 s 中长度为 k 的单个子字符串中可能包含的最大元音字母数。
英文中的 元音字母 为(a, e, i, o, u)。
代码1(过了,但是有bug):
class Solution {
public:
int maxVowels(string s, int k) {
int left = 0, right = 0;
int res = 0;
int now = 0;
while(right - left < k){
if(check(s[right])){
res++;
}
right++;
}
right--;
now = res;
while(right < s.length()){
if(check(s[++right])){
now++;
}
if(check(s[left++])){
now--;
}
res = max(res, now);
}
return res;
}
bool check(char c){
if(c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u'){
return true;
}
return false;
}
};
窗口右侧移动到最后一个字符时,会发生越界。
越界代码段:
while(right < s.length()){
if(check(s[++right])){
now++;
}
if(check(s[left++])){
now--;
}
res = max(res, now);
}
当right == s.length() - 1时,此时窗口移动到最右侧,但是还能进入循环,++right,此时发生越界访问s[s.length()];
编译器不报错的原因在于:
在C++中,使用std::string的索引进行越界访问时,默认情况下并不会抛出异常或报错。这是因为std::string的operator[]运算符并没有进行边界检查。
当你访问超出边界的索引时,operator[] 会直接返回该索引处的内存内容,即使它可能不属于字符串的有效范围。这可能会导致未定义行为(Undefined Behavior,UB),但不会抛出异常或产生明显的错误。
如何进行边界检查:
使用std::string::at()方法。
这个方法与operator[]类似,但会进行边界检查。如果访问超出范围,它会抛出一个std::out_of_range异常。
代码2(正确):
class Solution {
public:
int maxVowels(string s, int k) {
int left = 0, right = 0;
int res = 0;
int now = 0;
while(right - left < k){
if(check(s[right])){
res++;
}
right++;
}
right--;
now = res;
while(right < s.length() - 1){
if(check(s[++right])){
now++;
}
if(check(s[left++])){
now--;
}
res = max(res, now);
}
return res;
}
bool check(char c){
if(c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u'){
return true;
}
return false;
}
};
代码3(进一步优化):
class Solution {
public:
int maxVowels(string s, int k) {
int ans = 0, now = 0;
for (int i = 0; i < s.length(); i++) {
if (s[i] == 'a' || s[i] == 'e' || s[i] == 'i' || s[i] == 'o' || s[i] == 'u') {
now++;
}
if (i < k - 1) {
continue;
}
ans = max(ans, now);
char out = s[i - k + 1];
if (out == 'a' || out == 'e' || out == 'i' || out == 'o' || out == 'u') {
now--;
}
}
return ans;
}
};