【问题标题】:A specific test case will not pass the test somehow特定的测试用例不会以某种方式通过测试
【发布时间】:2016-12-05 08:58:29
【问题描述】:

代码的目的是基本上删除文本文件中存在的无用数组中的单词。我遇到了一个非常奇怪的问题,代码不会删除短语“waiting on the Shelf”中的“the”一词,但所有其他测试用例(很多)都通过了。有什么想法吗?

int main(){
    string useless[20] = { "an", "the" , "of", "to", "and", "but", "nor", "or", "some", "any", "very", "in", "on", "at", "before", "after", "into", "over", "through", "along"};

    ifstream fin("input.txt");
    if(fin.fail()){
        cout << "Input failed to open" << endl;
        exit(-1);
    }

    string line;
    getline(fin, line);
    getline(fin, line);
    getline(fin, line);
    getline(fin, line);

    ofstream fout("output.txt");

    while(getline(fin, line)){
        vector<string> vec;
        istringstream iss(line);
        while (iss) {
            string word;
            iss >> word;
            transform(word.begin(), word.end(), word.begin(), ::tolower);
            vec.push_back(word);
        }

        for(int i = 0; i < vec.size(); i++){
            for(int j = 0; j < 20; j++){
                if(vec[i] == useless[j]){
                    vec.erase(remove(vec.begin(), vec.end(), vec[i]), vec.end());
                }
            }
            fout << vec[i] << " ";
        }
        fout << endl;
    }
}

【问题讨论】:

  • 欢迎来到 Stack Overflow!听起来您可能需要学习如何使用调试器来逐步执行代码。使用好的调试器,您可以逐行执行您的程序,并查看它与您期望的偏差在哪里。如果您要进行任何编程,这是必不可少的工具。进一步阅读:How to debug small programs.
  • 是的,是的,我可以看到调试器将如何真正帮助我。我目前没有使用任何 IDE(只是 sublime 和终端),因此缺少调试器。
  • 您不需要 IDE 即可使用调试器 - 您只需从命令行使用 gdb。
  • 通过将main 中的内容拆分为两个或三个函数,在代码中添加更多结构也是一个好主意。

标签: c++ string vector token erase


【解决方案1】:

你在这里使用了不正确的迭代

 for(int i = 0; i < vec.size(); i++){
        for(int j = 0; j < 20; j++){
            if(vec[i] == useless[j]){
                vec.erase(remove(vec.begin(), vec.end(), vec[i]), vec.end());
            }
        }
        fout << vec[i] << " ";
    }
    fout << endl;
}

在此迭代之前,您拥有具有下一个值的向量:[waiting][on][the][shelf]。当 i == 1 时,您从向量中删除“on”,这样您就有了下一个向量 [waiting][the][shelf],但 i 索引仍然相等到 1,在下一次迭代中,您跳过“the”字,因为最后一个擦除操作重新组织了您的向量并将“the”字移动到删除的“on”位置。

您可以使用 remove_if。例如:

 vec.erase(remove_if(vec.begin(), vec.end(), [&]( const string& str )
 {
     return std::find(begin(useless), end(useless), str ) != end(useless);
 }), vec.end()); 

之后,您将获得过滤后的向量,useless 数组中没有单词。

顺便说一句,我们可以优化它。上面的算法具有下一个复杂度:O(vec_size*useless_size)。我们只能将其优化为 O(vec_size)。 您可以使用哈希集合(unordered_set)代替数组,它为您提供恒定的元素访问时间。

 unordered_set<string> useless = { "an", "the" , "of", "to", "and", "but", "nor", "or", "some", "any", "very", "in", "on", "at", "before", "after", "into", "over", "through", "along" };
 ...
 vec.erase(remove_if(vec.begin(), vec.end(), [&](const string& str)
 {
     return  useless.find(str) != useless.end();
 }), vec.end());

【讨论】:

  • 所以解决方案是在每次删除元素时重置迭代器?编辑:还是每次删除元素时都减少 i ?
  • 我会在答案中写出解决方案。
  • 您可以为 std::remove_if 方法编写自己的条件。对于 vec 中的每个元素,我正在尝试使用 std::find 方法在无用集合中查找元素。如果我找到它( std::find 的结果不等于数组的结尾),我返回 true (对于 std::remove_if 谓词,它的意思是:删除元素)。
猜你喜欢
  • 1970-01-01
  • 2022-08-14
  • 1970-01-01
  • 1970-01-01
  • 2014-01-04
  • 2017-10-30
  • 2019-05-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多