【问题标题】:How can I remove characters that appear consecutively more than two times from a string?如何从字符串中删除连续出现两次以上的字符?
【发布时间】:2021-05-13 05:18:01
【问题描述】:
#include <iostream>
#include <string>

using namespace std;

int main() {
    string str;
    cin >> str;
    
    int size;
    size = str.length();

for(int i=0;i<size;i++){                      
        for(int j=i+2;j<size;j++){
            if(str[i]==str[j])                  //detect str[i]>2
                cout<<str[i]<<endl;             //print str[i]>2
            else
                cout<<"no occurrences"<<endl;}
 }
}

这是我开始的代码。我的想法是循环字符串,直到一个字母连续出现两次以上,如果出现,则每隔一次删除一次,所以只剩下两个。

edit:添加了一个用于检测和打印 str[i]>2

的嵌套 for

【问题讨论】:

  • 超过2次,你的意思是连续的还是整个字符串?
  • @anirudh 连续
  • @JeremyFriesner 已修复 :)
  • 你的想法听起来还不错。尝试实现它。如果您遇到问题edit 并显示您的尝试。
  • @Scheff 我找到了嵌套循环的解决方案 :) 我无法理解使用 str.erase() 删除这些事件虽然????

标签: c++ string


【解决方案1】:

我有点难以发送我的答案 - 并让 OP 很高兴自己找到解决方案。

但是,我的解决方案没有使用std::string::erase()

#include <iostream>
#include <string>

int main()
{
  // get input
  std::string str;
  //std::cin >> str; // doesn't read white space
  std::getline(std::cin, str);
  std::cout << str << std::endl; // show input
  // check whether enough input is available
  size_t size = str.length();
  if (size < 3) return 0; // nothing to do
  // remove all occurrences of more than two equal consecutive characters
  char c0 = str[0], c1 = str[1]; // 1st and 2nd character
  size_t iW = 2; // write index
  for (size_t iR = 2; iR < size; ++iR) {
    char c2 = str[iR];
    if (c0 != c1 || c1 != c2) {
      str[iW++] = c2; // write character to keep
      c0 = c1; c1 = c2; // shift characters
    }
  }
  str.resize(iW); // clip string to new length
  // done
  std::cout << str << std::endl; // show output
}

输出:

Hellllo World
Hello World

Live Demo on coliru

std::string(或std::vector)之类的连续存储擦除容器中间的东西并不是很便宜的操作。反复这样做(以防万一)会使情况变得更糟。

原因是擦除中间的某些内容意味着有效地将所有后续元素向上移动。因此,由于两个嵌套循环,这可能会以二次复杂度 (O(n²)) 告终。

使用该解决方案,我改为使用一个循环完成所有操作 - 线性复杂度 (O(n)) - 更好。

实际上,我曾经在生产性工作中遇到过这种解决方案,其中输入数据太大,以至于我们(严格来说,对于我们的客户)无法接受二次复杂度,因为它需要很长时间。

【讨论】:

    【解决方案2】:

    感谢你的版本,这也是我的,正如你所说的效率较低

    #include <iostream>
    #include <string>
    using namespace std;
    
    
    int main(){
    string str;
        cin>>str;
        
    int size;
    size=str.length();
    
     for(int i=0;   i<size; i++){                      
    //detect str[i]>2
           for(int j=i+2;  j<size; j++){
                if(str[i]==str[j])                          
    //deletes at position
                    str.erase(i, 1);}
    }                      
    
        cout<<"new string is: "<<str<<endl;
        
        return 0;
    }
    

    正如你所说,擦除后大小不会改变,我该如何更新?

    也有特定的短语我得到这个错误

    eeeerzrrrttsjjjs
    terminate called after throwing an instance of 'std::out_of_range'
      what():  basic_string::erase: __pos (which is 13) > this->size() (which is 12)
    Aborted (core dumped)
    

    【讨论】:

    • 要么使用for (int i = 0; i &lt; str.size(); i++)(在内部循环中也是如此,并删除变量size)或者只是在你擦除的地方添加一个--size;。 (在这种情况下不要忘记{ }。)
    • 附注:std::string::length() 返回一个size_t,它具有适当的平台相关大小,但始终是无符号整数。因此,intsizeij 的不幸选择。 (使用适当的警告级别,您的编译器会告诉您这一点。)我建议只使用size_t
    • 顺便说一句。该错误正是由于size 在您删除某些内容后已过时这一事实造成的。因此,您的循环运行时间过长,最终对字符串str 进行了越界访问。您已经设法选择了一个合适的样本输入来证明这一点。 ;-)
    • 感谢@Scheff 一切正常,我学到了新东西。祝你有美好的一天:)
    猜你喜欢
    • 2020-11-22
    • 1970-01-01
    • 2020-06-16
    • 2022-07-22
    • 1970-01-01
    • 2019-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多