【问题标题】:Removing consecutive repeated characters in a string in C++在 C++ 中删除字符串中的连续重复字符
【发布时间】:2011-08-07 13:54:17
【问题描述】:

这是一个字符串问题。首先删除所有长度为1的重复连续子字符串,然后删除长度为2的子字符串,依此类推... 例如,如果我们有这样的字符串 -> abcababceccced 删除长度为 1 的子字符串后,我们将得到 abcababceced 删除长度为 2 的子字符串后,我们将得到 abcabced 删除长度为 3 的子字符串后,我们将得到 abced 这将是最终输出

我设计了一个算法,但它的复杂度为 O(n3),这根本不可取。我的算法如下

char str[20]="abcababceccced";
int len=strlen(a);
 for(i=1;i<=len/2;i++){
     for(j=0;j<len;){
      bool flag=chk(a,j,i);//this function will check whether the substring starting at a[j] and a[j+i] of length i are same or not.
       if(flag){
        //remove the second same substring.
       }
       else 
         j=j+i;
      }
  }

如果有人在 C++ 中针对这个特定问题提出一种不太复杂的算法,我将不胜感激。

【问题讨论】:

    标签: c++ string algorithm complexity-theory


    【解决方案1】:

    您可以通过相对于自身“滑动”字符串、逐个字符进行比较,然后查找匹配的位置来构建一些东西。例如:

    abcababceccced
    -abcababceccced
    -0000000001100-
    
    abcababceced
    --abcababceced
    --0001100110--
    

    不清楚它是否会更快,“按顺序”,但只是以不同的方式看待问题。

    【讨论】:

      【解决方案2】:

      确实,每个子字符串长度都可以使用线性时间,因为您只需要连续相同的子字符串。只需将计数器保留一个相同的字符,并在找到子字符串时更新字符串。由于您要删除所有可能长度的子字符串,因此总体复杂度是二次的。

      以下 C 代码应该可以工作:

      char str[20]="abcababceccced";
      int len = strlen(str);
      int i, j, counter;
      for(i = 1; i <= len / 2; ++i)
      {
         for(j = i, counter = 0; j < len; ++j)
         {
            if (str[j] == str[j - i])
               counter++;
            else
               counter = 0;
            if (counter == i)
            {
               counter = 0;
               memmove(str + j - i, str + j, (len - j) * sizeof(char));
               j -= i;
               len -= i;
            }
         }
         str[j] = 0;
         printf("%s\n", str);
      }
      

      这应该连续打印:

      abcababceced
      abcabced
      abced
      

      【讨论】:

        【解决方案3】:

        你可以一次性完成:

        #include <stdio.h>
        #include <string.h>
        
        int main()
        {
          char str[] = "abbbbcaaaababbbbcecccedeeed";
          int len = strlen(str);
          int read_pos, write_pos, prev_char;
        
          prev_char = str[0] + 1;
          for (read_pos = 0, write_pos = 0; read_pos < len; read_pos++)
          {
            if (str[read_pos] != prev_char)
            {
              str[write_pos] = str[read_pos];
              write_pos++;
            }
            prev_char = str[read_pos];
          }
          str[write_pos] = '\0';
        
          printf("str = %s\n", str);
          return 0;
        }
        

        由于您总是写入小于或等于读取位置的位置,因此您永远不会在使用之前销毁字符串。

        我已将 prev_char 初始化为与第一个字符完全不同的东西,但检查字符串的长度是否不为零是有意义的。

        【讨论】:

        • 这只是第一遍。
        • @AShelly:你完全正确。随意投反对票:-(。我觉得可以使用后缀树非常有效地解决原始问题。像这样:citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.46.6378
        • 为什么不将其添加到您的答案中而不是邀请反对票:)
        猜你喜欢
        • 2019-09-02
        • 1970-01-01
        • 2018-10-21
        • 1970-01-01
        • 2015-01-26
        • 1970-01-01
        • 2017-04-03
        • 2018-08-05
        • 2016-07-31
        相关资源
        最近更新 更多