从给定的字符串中查找给定长度的子序列?

时间:2012-08-03 18:44:14

标签: c++

要从给定长度的字符串中查找子序列,我有一个递归代码(如下所示),但是当字符串长度很大时需要很长时间....

void F(int index, int length, string str)
{
  if (length == 0) {
cout<<str<<endl;
//int l2=str.length();
//sum=0;
    //for(int j=0;j<l2;j++)
//sum+=(str[j]-48);
//if(sum%9==0 && sum!=0)
    //{c++;}
//sum=0;
  } else {
    for (int i = index; i < n; i++) {
      string temp = str;
      temp += S[i];
   //sum+=(temp[i]-48);
      F(i + 1, length - 1, temp);
    }
  }
}

请帮我一些实现非递归代码或其他内容的想法。

2 个答案:

答案 0 :(得分:1)

当输入字符串长度很大时,您提到当前代码太慢。如果你能提供一个具体的例子以及你的时间信息会很有帮助,所以我们知道你认为是什么&#34;太慢&#34;。您还应该指定您认为可接受的运行时间。这是一个例子:

我将从一个初始版本开始,我相信它与您当前的算法类似。它生成长度为> = 2的所有子序列:

#include <iostream>
#include <string>

void subsequences(const std::string& prefix, const std::string& suffix)
{
    if (prefix.length() >= 2)
        std::cout << prefix << std::endl;

    for (size_t i=0; i < suffix.length(); ++i)
        subsequences(prefix + suffix[i], suffix.substr(i + 1));
}

int main(int argc, char* argv[])
{
    subsequences("", "ABCD");
}

运行此程序会产生以下输出:

AB
ABC
ABCD
ABD
AC
ACD
AD
BC
BCD
BD
CD

现在让我们将输入字符串更改为更长的时间。我将使用26个字符的输入字符串:

"ABCDEFGHIJKLMNOPQRSTUVWXYZ"

这会生成67,108,837个子序列。我不会在这里列出它们:-)。在我的机器上,使用26个字符的输入字符串,上面显示的代码只需要超过78秒(不包括输出到cout)。

当我寻找优化上述代码的方法时,跳出来的一件事是它为每个递归调用子序列()创建了两个新的字符串对象。如果我们可以提前预先分配空间然后简单地传递指针怎么办?第2版​​:

#include <stdio.h>
#include <malloc.h>
#include <string.h>

void subsequences(char* prefix, int prefixLength, const char* suffix)
{
    if (prefixLength >= 2)
        printf("%s\n", prefix);

    for (size_t i=0; i < strlen(suffix); ++i) {
        prefix[prefixLength] = suffix[i];
        prefix[prefixLength + 1] = '\0';
        subsequences(prefix, prefixLength + 1, suffix + i + 1);
    }
}

int main(int argc, char* argv[])
{
    const char *inputString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    char *prefix = (char*) _malloca(strlen(inputString) + 1);

    subsequences(prefix, 0, inputString);
}

这会生成相同的67,108,837个子序列,但执行时间现在只超过2秒(同样,不包括printf的输出)。

答案 1 :(得分:0)

您的代码可能很慢,因为您的字符串很大。对于n个唯一元素的序列,存在长度为k的(n个k)子序列。这意味着对于序列“ABCDEFGHIJKLMNOPQRSTUVWXYZ”,有长度为13的10.400.600个不同的子序列。这个数字增长得非常快。

然而,既然你问过,这里是一个非递归函数,它接受字符串 str 和大小 n 并打印所有长度为 n <的子序列< / em>的那个字符串。

void print_subsequences(const std::string& str, size_t n)
{
    if (n < 1 || str.size() < n)
    {
        return;  // there are no subsequences of the given size
    }
    // start with the first n characters (indexes 0..n-1)
    std::vector<size_t> indexes(n);
    for (size_t i = 0; i < n; ++i)
    {
        indexes[i] = i;
    }
    while (true)
    {
        // build subsequence from indexes
        std::string subsequence(n, ' ');
        for (size_t i = 0; i < n; ++i)
        {
            subsequence[i] = str[indexes[i]];
        }
        // there you are
        std::cout << subsequence << std::endl;
        // the last subsequence starts with n-th last character
        if (indexes[0] >= str.size() - n)
        {
            break;
        }
        // find rightmost incrementable index
        size_t i = n;
        while (i-- > 0)
        {
            if (indexes[i] < str.size() - n + i)
            {
                break;
            }
        }
        // increment that index and set all following indexes
        size_t value = indexes[i];
        for (; i < n; ++i)
        {
            indexes[i] = ++value;
        }
    }
}