我正在用代码战做kata,我需要这样的东西:
当字符串中的字母出现两次时,将两者都删除。
我已经做了类似的事情:
std::string str2 = str;
for(int i=0;i<str2.size();i++){
for(int j=0;j<str2.size();j++){
if(std::tolower(str2[i]) == std::tolower(str2[j]) && j != i){
n++;
str2.erase(str2.begin() + i);
str2.erase(str2.begin() + j);
i--;
j--;
}
}
}
并丢弃核心(这是由str2.erase(str2.begin() + i);
引起的)。我知道这是我记忆中的错误,但是您能告诉我这是怎么回事吗?我分析了,没有发现任何不良情况。
答案 0 :(得分:1)
您正在从str2
中删除两个字符。如果i
小于j
,则可能导致第二次擦除操作超出字符串的末尾(即使不是,也将擦除错误的字符)。
答案 1 :(得分:0)
首先,我们可以观察到,发生删除操作时,我们将始终拥有i<j
。
现在,如果先删除第一个字符,然后删除第二个字符,则是在移动的目标上射击:删除第一个字符后,需要调整到第二个字符的新位置:
str2.erase(str2.begin() + i);
str2.erase(str2.begin() + j-1); // because former j c[j] is now c[j-1]
另一个合适的变体是先删除第二个字符(不更改第一个字符的位置):
str2.erase(str2.begin() + j); // because j> i it has no impact on i
str2.erase(str2.begin() + i);
不相关,但是我们也可以利用对i<j
的推论来优化或循环并保存大量无用的比较:
for(int i=0;i<str2.size();i++) {
for(int j=i+1;j<str2.size();j++) {
...
}
}
另一个问题是,当i--
不递增时,您会在内循环中执行i
。这将带来两个后果,您将重做已经进行的比较。因此,只需删除此减量,然后以j=i+1
重新开始即可。
您的算法仅删除字母对。因此,如果您多次出现一个字母,则只会删除前两个字母。因此,您需要检查算法(注意不要擦除第一次出现的几次;-))