从C ++中的字符串中删除一个字符

时间:2016-09-28 00:17:42

标签: c++

我知道已经存在使用#include <algorithm>的解决方案,但我想知道以下是否可行的方法:

#include <iostream>
using namespace std;
void remove_character_from_result(string& result, char remove){
    int size = result.size(); 
    for (int i = 0; i < size; i++){
        int pos = result.find(remove); 
        if(pos == result.npos) break;
            else{
                if(pos == 0)
                    result = result.substr(1); 
                else
                    result = result.substr(0, pos) + result.substr(pos + 1);
            }
    }
}
int main() {
    string result = "Asad Ahmad";
    remove_character_from_result(result, 'A');
    cout << result << endl;
    return 0;
}

我已经针对正常的测试用例测试了我的代码,它似乎确实有效,我不确定时间复杂度是否会比result.erase(remove(result.begin(), result.end(), 'A'), result.end());更好,如果任何人可以对此有所了解:) PS我为不使用引用而不是指针或&#39; *&#39;而道歉。而不是&#39; - &gt;&#39;早些时候 - 这是我写的代码,我并不为此感到自豪......

2 个答案:

答案 0 :(得分:3)

您的代码有各种各样的问题。

#include <iostream>

如果您要访问std::string课程,则需要#include <string>。您不应该依赖<iostream>

包含它
using namespace std;

这是一种可怕的做法,使用std中的所有名称来污染您的全局命名空间。如果您想避免重复特定名称,请选择语法

using std::string;

例如。

void remove_character_from_result(string* result, char remove){

您的代码不会检查此指针是否为空。最好通过引用来获取参数。

void remove_character_from_result(string& result, char remove){

int size = (*result).size(); 

虽然(*result).size()达到了目的,但您应该使用->来提醒自己正在使用指针,并且可能记得检查它是否为空。

size = result->size();

这里我们也遇到了程序中的错误:

int size = result->size();

size()会返回一个std::string::size_type,它是无符号的,可能会显着大于int。一旦字符串大于std::numeric_limits<int>::max(),您的代码就会停止工作。

这应该是

auto size = result->size();

std::string::size_type size = result->size();

for (int i = 0; i < size; i++){

我们再次遇到尺寸问题,但我们也遇到了在操作过程中尺寸可能会发生变化的问题。您应该用以下代码替换这两行:

for (std::string::size_type i = 0; i < result->size(); ++i) {

下一段代码:

    int pos = (*result).find(remove); 
    if(pos == (*result).npos) break;
        else{
            if(pos == 0)
                *result = (*result).substr(1); 
            else
                *result = (*result).substr(0, pos) + (*result).substr(pos + 1);

没有多大意义,并且做事很难。在第一种情况下,您创建一个新的子字符串,然后将其复制到您自己。在第二种情况下,您创建两个临时子串,您将它们一起添加到第三个,然后将其复制到自己。

最好使用erase

还不清楚为什么你首先要有尺寸约束的循环。

你最好用这样的东西替换整个函数:

#include <iostream>
#include <string>

void remove_character_from_result(std::string& result, char remove) {
   for (size_t pos = 0; (pos = result.find(remove, pos)) != result.npos; ) {
       size_t end = pos + 1;
       while (end < result.size() && result[end] == remove)
           ++end;
       result.erase(pos, end - pos);
   }
}

int main() {
    std::string s = "hello world";
    remove_character_from_result(s, 'l');
    std::cout << s << '\n';
}

最坏情况下的时间复杂度是它必须删除一半的字符,即O(NlogN)。

您可以通过从右侧而不是左侧进行操作来提高性能:考虑从“ababab”中删除字符“a”。第一次擦除之后是复制5个字符,第二个擦除3个字符,第三个擦除1个字符。如果我们以相反的方式工作,第一个擦除将是1个字符,第二个擦除2和第三个擦除3。

答案 1 :(得分:0)

如果您真的坚持自己这样做,您可能希望使用string的成员函数进行搜索。对于(可能微小的)效率增益,您还希望从结束回到字符串的开头进行搜索。我也会通过引用传递字符串而不是传递指针。

最后,您不必用子串创建一个新字符串,也可以删除想要删除的字符:

void remove_character(string &result, char remove) {   
    std::string::size_type pos;
    while ((pos = result.rfind(remove)) != std::string::npos)
        result.erase(pos, 1);
}

如果您想要优化一点(或可能甚至更多),您可以从找到上一个实例的点恢复第二次和后续搜索:

void remove_character(string &result, char remove) {   
    std::string::size_type pos = std::string::npos;
    while ((pos = result.rfind(remove, pos)) != std::string::npos)
        result.erase(pos, 1);
}