从字符串中删除重复字符的功能仅部分适用于相邻字符

时间:2015-12-07 02:04:34

标签: c++ string

我知道这是一个经常被问到的问题并且如果它是愚蠢的而道歉,但我正在尝试从文件中的字符串中删除重复的字符并将新字符串放入另一个文件中。那部分情况正常。

我遇到的主要问题是使用我的算法去除字符,它只适用于相同的连续字符,甚至只是部分字符。我试图在for循环中使用.erase()来执行此操作,但正如我所说它不起作用。我哪里错了?

string removeRepeats(string strIn,string &strOut){
    int i;
    int len = strIn.length();
    for(i = 0;i < len; i++){
        if(strIn[i] == strIn[i+1]){
            strIn.erase(i+1,1);
        }
        len = strIn.length();
    }
    return strOut = strIn;
}

这些是来自示例文件的输入字符串的字符串:

aaaaaabbccccc
nnnnmmmvvv
rocko 
refrigerate pool 
fungus 

这是他们在程序运行后出现的结果:

aaabccc                                                                                                                                                 
nnmmvv                                                                                                                                                  
rocko                                                                                                                                                   
refrigerate                                                                                                                                             
pol                                                                                                                                                     
fungus  

2 个答案:

答案 0 :(得分:2)

您只检查相邻字符:if(strIn[i] == strIn[i+1]) { ...

你可以更有效地做到这一点,但我想先做一些评论:

返回按引用传递,但不能同时传递

  • 您可以通过引用返回strOut 传递strOut。你应该选择其中一个。在我下面写的代码中,我选择返回strOut

最小化变量的范围

  • 与C不同,在C ++中,您可以在for - 循环中初始化变量。除了循环变量之外,您还希望尝试最小化其他变量的范围。在代码中,您可以创建变量len。如果您使用了for(size_t i = 0; i < strIn.length(); ++i),则无需在if - 语句后更新它。

返回作业只是简单的怪异的

  • return strOut = strIn;很奇怪。你不会经常在C ++中看到这一点(参见返回通过引用传递,但不能同时传递)。如果您真的想要return strOut,那么在更改strIn并在副本上执行所有字符串突变之前创建std::string removeRepeats(std::string strIn){ std::string strOut = strIn; for(size_t i = 0;i < strOut.length(); ++i){ if(strOut[i] == strOut[i+1]){ strOut.erase(i+1,1); } } return strOut; } 的副本会更有意义。

以下是我对您的代码所做的更改(无论算法的正确性如何):

std::string remove_repeats(std::string input_string) {
  // You have seen no characters yet
  bool seen[128] = { false }; 

  std::string output_string = "";

  // for every character in the string
  for(auto c: input_string) {
    // if we haven't seen the the ASCII yet
    if(!seen[128-c]) {
      // append it to our output string
      output_string+=c;
      // mark the letter as seen
      seen[128-c] = true;
    }
  }

  return output_string;
}

这会更清洁,你会发现。

现在解决您的问题。

由于只有128个ASCII字符,您可以创建一个布尔数组并检查您之前是否看过某个字符。

因为你想保留重复字符的最后,我们需要有点棘手。下面的代码将保留重复字符的第一个

C ++ 11批准

std::string remove_repeats(std::string input_string) {
  // You have seen no characters yet
  bool seen[128] = { false };  

  std::string output_string = "";

  // for every character in the string
  for(size_t i = 0; i < input_string.length(); ++i) {
    char c = input_string[i];
    // if we haven't seen the the ASCII yet
    if(!seen[128-c]) {
      // append it to our output string
      output_string+=c;
      // mark the letter as seen
      seen[128-c] = true;
    }
  }

  return output_string;
}

这是ideone

如果你不能使用C ++ 11,你可以这样做:

std::string remove_repeats(std::string input_string) {
  // You have seen no characters yet
  bool seen[128] = { false };  

  // Reverse the input string
  std::reverse(input_string.begin(), input_string.end());

  std::string output_string = "";

  // for every character in the string
  for(auto c: input_string) {
    // if we haven't seen the the ASCII yet
    if(!seen[128-c]) {
      // append it to our output string
      output_string+=c;
      // mark the letter as seen
      seen[128-c] = true;
    }
  }

  // Reverse the output string
  std::reverse(output_string.begin(), output_string.end());

  return output_string;
}

这是非C ++ 11版本的ideone

然而

你想保留最后一个。这是它变得有趣的地方。

如果我们反转字符串(1),运行我们的算法(2),然后重新反转(3),我们将获得所需的输出:

  

(1)“你好世界” - &gt; “dlrow olleh”

     

(2)“dlrow olleh” - &gt; “dlrow eh”

     

(3)“dlrow eh” - &gt; “他的世界”

以下是如何执行此操作:

#include <algorithm>

std::reverse确保dispatch_async(dispatch_get_main_queue()) { () -> Void in if let object = currentObject.objectForKey("postText") as? String { postTextView.text = "the text field has some text added" } }

最终工作ideone

答案 1 :(得分:1)

所以你需要做的是在寻找重复字符时你是一个嵌套for循环你现有的for循环所以:

string removeRepeats(string strIn,string &strOut){
int i;
int k;
int len = strIn.length();
for(i = 0;i < len; i++){
    for(k = i+1 ; k < len; k++){

        if(strIn[i] == strIn[k]){
            strIn.erase(k,1);
            k--;
        }
    }
    len = strIn.length();
}
return strOut = strIn;
}

这将修复程序的比较部分。你的问题在于你的代码只检查了每个数字,而不是所有其他字符