字符串擦除()给核心转储

时间:2018-12-01 16:13:21

标签: c++ erase

我正在用代码战做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);引起的)。我知道这是我记忆中的错误,但是您能告诉我这是怎么回事吗?我分析了,没有发现任何不良情况。

2 个答案:

答案 0 :(得分:1)

您正在从str2中删除两个字符。如果i小于j,则可能导致第二次擦除操作超出字符串的末尾(即使不是,也将擦除错误的字符)。

答案 1 :(得分:0)

首先,我们可以观察到,发生删除操作时,我们将始终拥有i<j

问题1

现在,如果先删除第一个字符,然后删除第二个字符,则是在移动的目标上射击:删除第一个字符后,需要调整到第二个字符的新位置:

        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);

优化1

不相关,但是我们也可以利用对i<j的推论来优化或循环并保存大量无用的比较:

for(int i=0;i<str2.size();i++) {
    for(int j=i+1;j<str2.size();j++) {
    ...
    }
}

优化2

另一个问题是,当i--不递增时,您会在内循环中执行i。这将带来两个后果,您将重做已经进行的比较。因此,只需删除此减量,然后以j=i+1重新开始即可。

Online demo

问题2(留作练习)

您的算法仅删除字母对。因此,如果您多次出现一个字母,则只会删除前两个字母。因此,您需要检查算法(注意不要擦除第一次出现的几次;-))