生成不同字符串的非递归组合算法
Posted
技术标签:
【中文标题】生成不同字符串的非递归组合算法【英文标题】:Non-recursive combination algorithm to generate distinct character strings 【发布时间】:2013-12-23 06:28:58 【问题描述】:这个问题困扰我太久了。我需要C
中的非递归算法来生成不明确的字符串。例如,如果给定字符串的长度为26
个字符,并且该字符串的长度为2
,则存在26^2
非不同字符。
请注意,这些是不同的组合,aab
与 baa
或 aba
不同。我搜索了 S.O.,大多数解决方案都会产生不明显的组合。另外,我不需要排列。
算法不能依赖库。我将把这段 C 代码翻译成标准 C 库不能工作的 cuda(至少效率不高)。
在向您展示我开始的内容之前,让我解释一下程序的一个方面。它在 GPU 上是多线程的,所以我用几个字符初始化开始字符串,在本例中为 aa
。为了创建一个组合,我根据所需的长度添加一个或多个字符。
这是我尝试过的一种方法:
int main(void)
//Declarations
char final[12] = 0;
char b[3] = "aa";
char charSet[27] = "abcdefghijklmnopqrstuvwxyz";
int max = 4; //Set for demonstration purposes
int ul = 1;
int k,i;
//This program is multithreaded on a GPU. Each thread is initialized
//to a starting value for the string. In this case, it is aa
//Set final with a starting prefix
int pref = strlen(b);
memcpy(final, b, pref+1);
//Determine the number of non-distinct combinations
for(int j = 0; j < length; j++) ul *= strlen(charSet);
//Start concatenating characters to the current character string
for(k = 0; k < ul; k++)
final[pref+1] = charSet[k];
//Do some work with the string
...
很明显,这个程序没有任何用处,如果我只是从charSet
中附加一个字符,请接受。
我的教授建议我尝试使用映射(这不是家庭作业;我向他询问了在没有递归的情况下生成不同组合的可能方法)。
他的建议与我上面开始的类似。使用计算出的组合数,他建议按照mod 10
进行分解。然而,我意识到这行不通。
例如,假设我需要附加两个字符。这给了我 676 个使用上述字符集的组合。如果我是第 523 个组合,他演示的分解将产生
523 % 10 = 3
52 % 10 = 2
5 % 10 = 5
显然这不起作用。第一,它产生三个字符,第二,如果我的字符集大于 10 个字符,映射会忽略索引 9 以上的那些。
不过,我相信映射是解决方案的关键。
我探索的另一种方法用于循环:
//Psuedocode
c = charset;
for(i = 0; i <length(charset); i++)
concat string
for(j = 0; i <length(charset); i++)
concat string
for...
但是,这会硬编码我要计算的字符串的长度。我可以使用带有goto
的if
语句来破坏它,但我想避免这种方法。
感谢任何建设性的意见。
【问题讨论】:
提示:如何在不递归的情况下生成数字 0-9999?除了您使用的是 base-26 之外,您的问题完全相同。 @R.. 不知道这是不是你的意思,但我会简单地做一个 for 循环并将一些整数变量增加到所需的最大值。 没错。所以你的问题是如何对字符数组中表示的 base-26 数字做同样的事情。首先在纸上计算如何使用以 10 为底的数字来处理数字。顺便说一句,使用前导零,所以 0 是 0000 或其他。 @R.. 和 1 是 0001。如果是这种情况,您是否实质上建议像在映射中那样为每个“字符”分配一个唯一编号? (假设我们仍在 base-10 中)。 好吧,如果您使用以 10 为底的数字,是的,您首先从 0000 到 0001,然后到 0002,依此类推,直到到达 0009。接下来会发生什么?跨度> 【参考方案1】:给定一个字符串,查找序列中下一个可能的字符串:
在字符串中查找不是字母表中最后一个字符的最后一个字符。
用字母表中的下一个字符替换它。
将该字符右侧的每个字符更改为字母表中的第一个字符。
从一个重复字母表第一个字符的字符串开始。当第 1 步失败时(因为字符串是字母表的最后一个字符),那么你就完成了。
例如:字母表是"ajxz"
。
以aaaa
开头。
第一次迭代:不是z
的最右边的字符是最后一个。将其更改为下一个字符:aaaj
第二次迭代。同上。 aaax
第三次迭代:再次。 aaaz
四次迭代:现在最右边的非z
字符是倒数第二个。推进它并将所有字符向右更改为a
:aaja
等等
【讨论】:
在决赛周和剥夺睡眠的日子里,是的。谢谢。【参考方案2】:首先,感谢大家的意见;这很有帮助。由于我正在将此算法转换为 cuda,因此我需要它在 GPU 上尽可能高效。提出的方法确实有效,但不一定对 GPU 架构是最佳的。我使用模块化算法提出了一个不同的解决方案,该解决方案利用了我的字符集的基础。这是一个示例程序,主要在C
中混合C++
用于输出,而且速度相当快。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
typedef unsigned long long ull;
int main(void)
//Declarations
int init = 2;
char final[12] = 'a', 'a';
char charSet[27] = "abcdefghijklmnopqrstuvwxyz";
ull max = 2; //Modify as need be
int base = strlen(charSet);
int placeHolder; //Maps to character in charset (result of %)
ull quotient; //Quotient after division by base
ull nComb = 1;
char comb[max+1]; //Array to hold combinations
int c = 0;
ull i,j;
//Compute the number of distinct combinations ((size of charset)^length)
for(j = 0; j < max; j++) nComb *= strlen(charSet);
//Begin computing combinations
for(i = 0; i < nComb; i++)
quotient = i;
for(j = 0; j < max; j++) //No need to check whether the quotient is zero
placeHolder = quotient % base;
final[init+j] = charSet[placeHolder]; //Copy the indicated character
quotient /= base; //Divide the number by its base to calculate the next character
string str(final);
c++;
//Print combinations
cout << final << "\n";
cout << "\n\n" << c << " combinations calculated";
getchar();
【讨论】:
以上是关于生成不同字符串的非递归组合算法的主要内容,如果未能解决你的问题,请参考以下文章