3

得到答案后编辑

这里有一些很好的答案。我喜欢 Josh 的,因为它非常聪明并且使用 C++。但是,我决定接受 Dave 的回答,因为它简单且具有递归性。我对它们都进行了测试,它们都产生了相同的正确结果(尽管顺序不同)。所以再次感谢大家。


假设我有一个字符串 s 的字符 s[0]:s[N] 并且每个字符 s[i] <= s[i+1] 例如字符串

aaacdddghzz

我想生成子字符串的所有组合,同时保持字符之间的相同关系。

所以例如我会得到

a
aa
aaa
ad
aad
aaad
add
aadd
aaadd
addd
aaddd
aaaddd
d
dd
ddd
.
.
.
ac
aac
.
.
.
acdddghzz
aacdddghzz
aaacdddghzz

但不是

ca
hdz
...etc

现在我知道如何计算出有多少种组合。您创建字符串中字母频率的直方图。所以在上面的例子中,那将是

对于字符串 aaacdddghzz

a=3
d=3
c=1
g=1
h=1
z=2

公式是(a+1)(c+1)(d+1)(g+1)(h+1)(z+1) = 4*4*2*2*2*3 = 384。有 384 个子字符串保持 s[i] <=s [i+1] 关系。

所以问题是如何递归地生成这 384 个子字符串?实际上,迭代方法同样好,也许更好,因为具有许多唯一字符的大字符串可能会导致堆栈溢出。这听起来像是家庭作业,但事实并非如此。我只是想出这样的算法没用。我使用 C++,但伪代码会很好。

4

5 回答 5

5

对 Ryan Shaw 上述回答的修正:

不是以二进制计数,而是根据每个字母的数量计算基数中的每个数字。例如:

a d c g h z
3 3 1 1 1 2

所以算了:

0 0 0 0 0 0
0 0 0 0 0 1
0 0 0 0 0 2
0 0 0 0 1 0
0 0 0 0 1 1 
0 0 0 0 1 2
0 0 0 1 0 0
...
0 0 0 1 1 2
0 0 1 0 0 0
...
0 0 1 1 1 2
0 1 0 0 0 0 
...
0 3 1 1 1 2
1 0 0 0 0 0
...
3 3 1 1 1 2

而且您已经枚举了所有可能的子集,没有重复。对于其中任何一个,输出字符串只是循环数字并输出指定数量的每个字母的问题。

1 2 0 0 1 1 => addhz
3 0 0 0 1 2 => aaahzz

和代码:

void GetCounts(const string &source, vector<char> &characters, vector<int> &counts)
{
    characters.clear();
    counts.clear();

    char currentChar = 0;
    for (string::const_iterator iSource = source.begin(); iSource != source.end(); ++iSource)
    {
        if (*iSource == currentChar)
            counts.back()++;
        else
        {
            characters.push_back(*iSource);
            counts.push_back(1);
            currentChar = *iSource;
        }
    }
}

bool Advance(vector<int> &current, const vector<int> &max)
{
    if (current.size() == 0)
        return false;

    current[0]++;
    for (size_t index = 0; index < current.size() - 1 && current[index] > max[index]; ++index)
    {
        current[index] = 0;
        current[index + 1]++;
    }
    if (current.back() > max.back())
        return false;
    return true;
}

string ToString(const vector<int> &current, const vector<char> &characters)
{
    string result;
    for (size_t index = 0; index < characters.size(); ++index)
        for (int i = 0; i < current[index]; ++i)
            result += characters[index];
    return result;
}

int main() { 
    vector<int> max;
    vector<char> characters;

    GetCounts("aaadddcghzz", characters, max);

    vector<int> current(characters.size(), 0);
    int index = 1;
    while (Advance(current, max))
    {
        cout << index++ << ":" << ToString(current, characters) << endl;
    }
}
于 2009-05-22T04:28:14.053 回答
2

以下是生成所有子序列的递归算法。

/* in C -- I hope it will be intelligible */

#include <stdio.h>

static char input[] = "aaabbbccc";
static char output[sizeof input];

/* i is the current index in the input string
 * j is the current index in the output string
 */
static void printsubs(int i, int j) {
    /* print the current output string */
    output[j] = '\0';
    printf("%s\n", output);
    /* extend the output by each character from each remaining group and call ourselves recursively */
    while(input[i] != '\0') {
        output[j] = input[i];
        printsubs(i + 1, j + 1);
        /* find the next group of characters */
        do ++i;
        while(input[i] == input[i - 1]);
    }
}

int main(void) {
    printsubs(0, 0);
    return 0;
}

如果您的兴趣只是计算有多少子序列,您可以更有效地完成它。只需计算每个字母的数量,将每个值加 1,然后将它们相乘。在上面的示例中,有 3 个 a、3 个 b、3 个 c 和 2 个 d,对于 (3 + 1) * (3 + 1) * (3 + 1) * (2 + 1) = 192 个子序列。这样做的原因是您可以在 0 和 3 a、0 和 3 b、0 和 3 c、0 和 2 d 之间进行选择,所有这些选择都是独立的

于 2009-05-22T04:20:32.957 回答
1

实际上,您的问题是列出给定集合中的所有子集。

考虑集合 {a,a,a,d,d,d,c,g,h,z,z},您的目标是按顺序列出其所有唯一子集,除了空集: {a} {a, a} {a,a,a} {a,a,a,d}

有一种快速列出给定集合中所有子集的方法。

我们以 {ABC} 为例:

{}     = 000
{C}    = 001
{B}    = 010
{BC}   = 011
{A}    = 100
{AC}   = 101
{AB}   = 110
{ABC}  = 111

看到图案了吗?只需使用从 0 增长到 2^n - 1 的整数。如果整数的第 i 个数字是 1,则从集合中获取第 i 个元素。

注意:由于在您的示例中,字符串中有重复项;因此,在生成之后,您可能需要删除重复项。

希望这可以帮到你。

于 2009-05-22T04:14:39.723 回答
0

好吧,在我看来,一种与您的解决方案类似但与您的输出不匹配的解决方案(不过,请参阅我对问题的评论),就是简单地遍历原始字符串的尾部列表(例如,对于“abc”,遍历“abc”,“bc”和“c”),并为每个生成前缀列表(“abc”,“ab”,“a”,然后是“bc”,“b” ,然后是“c”)。这与您想要的相比如何?

于 2009-05-22T04:17:16.170 回答
0

我使用了这个 java 代码(http://www.merriampark.com/comb.htm),只得到了 383 个。代码生成了太多的重复项,所以我不得不扔掉很多。我最终只得到了 383 个(请参见下文)。您可能想查看 stl 中 next-combinatiom 的 c++ 代码(但我在任何地方都找不到源代码)。电源组可能是最好的方法(但你也可能有重复)。

a
aa
aaa
aaac
aaacg
aaacgh
aaacghz
aaacghzz
aaacgz
aaacgzz
aaach
aaachz
aaachzz
aaacz
aaaczz
aaad
aaadc
aaadcg
aaadcgh
aaadcghz
aaadcghzz
aaadcgz
aaadcgzz
aaadch
aaadchz
aaadchzz
aaadcz
aaadczz
aaadd
aaaddc
aaaddcg
aaaddcgh
aaaddcghz
aaaddcghzz
aaaddcgz
aaaddcgzz
aaaddch
aaaddchz
aaaddchzz
aaaddcz
aaaddczz
aaaddd
aaadddc
aaadddcg
aaadddcgh
aaadddcghz
aaadddcghzz
aaadddcgz
aaadddcgzz
aaadddch
aaadddchz
aaadddchzz
aaadddcz
aaadddczz
aaadddg
aaadddgh
aaadddghz
aaadddghzz
aaadddgz
aaadddgzz
aaadddh
aaadddhz
aaadddhzz
aaadddz
aaadddzz
aaaddg
aaaddgh
aaaddghz
aaaddghzz
aaaddgz
aaaddgzz
aaaddh
aaaddhz
aaaddhzz
aaaddz
aaaddzz
aaadg
aaadgh
aaadghz
aaadghzz
aaadgz
aaadgzz
aaadh
aaadhz
aaadhzz
aaadz
aaadzz
aaag
aaagh
aaaghz
aaaghzz
aaagz
aaagzz
aaah
aaahz
aaahzz
aaaz
aaazz
aac
aacg
aacgh
aacghz
aacghzz
aacgz
aacgzz
aach
aachz
aachzz
aacz
aaczz
aad
aadc
aadcg
aadcgh
aadcghz
aadcghzz
aadcgz
aadcgzz
aadch
aadchz
aadchzz
aadcz
aadczz
aadd
aaddc
aaddcg
aaddcgh
aaddcghz
aaddcghzz
aaddcgz
aaddcgzz
aaddch
aaddchz
aaddchzz
aaddcz
aaddczz
aaddd
aadddc
aadddcg
aadddcgh
aadddcghz
aadddcghzz
aadddcgz
aadddcgzz
aadddch
aadddchz
aadddchzz
aadddcz
aadddczz
aadddg
aadddgh
aadddghz
aadddghzz
aadddgz
aadddgzz
aadddh
aadddhz
aadddhzz
aadddz
aadddzz
aaddg
aaddgh
aaddghz
aaddghzz
aaddgz
aaddgzz
aaddh
aaddhz
aaddhzz
aaddz
aaddzz
aadg
aadgh
aadghz
aadghzz
aadgz
aadgzz
aadh
aadhz
aadhzz
aadz
aadzz
aag
aagh
aaghz
aaghzz
aagz
aagzz
aah
aahz
aahzz
aaz
aazz
ac
acg
acgh
acghz
acghzz
acgz
acgzz
ach
achz
achzz
acz
aczz
ad
adc
adcg
adcgh
adcghz
adcghzz
adcgz
adcgzz
adch
adchz
adchzz
adcz
adczz
add
addc
addcg
addcgh
addcghz
addcghzz
addcgz
addcgzz
addch
addchz
addchzz
addcz
addczz
addd
adddc
adddcg
adddcgh
adddcghz
adddcghzz
adddcgz
adddcgzz
adddch
adddchz
adddchzz
adddcz
adddczz
adddg
adddgh
adddghz
adddghzz
adddgz
adddgzz
adddh
adddhz
adddhzz
adddz
adddzz
addg
addgh
addghz
addghzz
addgz
addgzz
addh
addhz
addhzz
addz
addzz
adg
adgh
adghz
adghzz
adgz
adgzz
adh
adhz
adhzz
adz
adzz
ag
agh
aghz
aghzz
agz
agzz
ah
ahz
ahzz
az
azz
c
cg
cgh
cghz
cghzz
cgz
cgzz
ch
chz
chzz
cz
czz
d
dc
dcg
dcgh
dcghz
dcghzz
dcgz
dcgzz
dch
dchz
dchzz
dcz
dczz
dd
ddc
ddcg
ddcgh
ddcghz
ddcghzz
ddcgz
ddcgzz
ddch
ddchz
ddchzz
ddcz
ddczz
ddd
dddc
dddcg
dddcgh
dddcghz
dddcghzz
dddcgz
dddcgzz
dddch
dddchz
dddchzz
dddcz
dddczz
dddg
dddgh
dddghz
dddghzz
dddgz
dddgzz
dddh
dddhz
dddhzz
dddz
dddzz
ddg
ddgh
ddghz
ddghzz
ddgz
ddgzz
ddh
ddhz
ddhzz
ddz
ddzz
dg
dgh
dghz
dghzz
dgz
dgzz
dh
dhz
dhzz
dz
dzz
g
gh
ghz
ghzz
gz
gzz
h
hz
hzz
z
zz
于 2009-05-22T05:06:00.857 回答