要从给定长度的字符串中查找子序列,我有一个递归代码(如下所示),但是当字符串长度很大时需要很长时间....
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);
}
}
}
请帮我一些实现非递归代码或其他内容的想法。
答案 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;
}
}
}