(再帰なし)は、個々の数字の和によって配列のn桁の数字を生成します

StackOverflow https://stackoverflow.com/questions/1715304

質問

私は、シーケンスが、個々の数字の合計によって決定され、次の順序では、n桁の数字のすべての可能な値を生成するために探しています。

たとえば、n = 3

111     sum = 3
112     sum = 4
121
211
122     sum = 5
212
221
113
131
311
114     sum = 6
141
411
:::
999     sum = 27

和グループ内の順序は重要ではありません。

すべてのヘルプ、アイデアをいただければ幸いです。

役に立ちましたか?

解決

あなたは、重要なデータの独自のスタックを維持する場合は、

あなたはは常には、反復一つに再帰的な問題を回すことができる - 再帰を避ける理由は、言語がそれをサポートしていないということであればそれはです

しかし、言語は、のないのそれをサポートする場合は、再帰的なソリューションは、はるかにエレガントされます。

私は再帰を避けるために考えることができる唯一の他の理由は、限られたスタックの深さです。その場合、再帰溶液の反復変換は、できるだけ多くのスタック空間を必要としないことで問題を緩和します。

しかし、あなたは処理n個の数字のスタックの深さが唯一の<サブ> 10 Nをログに記録するように相対的な成長ということを理解する必要があります。言い換えれば、あなただけ(32ビット整数の完全な範囲を処理するためにのみ10スタック・フレーム)の桁ごとに余分なスタックフレームを取得します。

のほかにのあなたは、その点に到達する時間によって、あなたは、アルゴリズムを実行するのは時間がかかりますね、スタックフレームは、あなたの問題の少なくともになります: - )

ここでは、再帰的なPythonのソリューションです。

def recur (numdigits,sum,pref="",prefsum=0):
    if numdigits == 0:
        if prefsum == sum:
            print "%s, sum=%d"%(pref,prefsum)
    else:
        for i in range (1,10):
            recur (numdigits-1,sum,"%s%d"%(pref,i),prefsum+i)

def do (n):
    for i in range (1,n*9+1):
        recur (n,i)

do (2)
do (3)

出力する(2および3):

11, sum=2          111, sum=3
12, sum=3          112, sum=4
21, sum=3          121, sum=4
13, sum=4          211, sum=4
22, sum=4          113, sum=5
31, sum=4          122, sum=5
14, sum=5          131, sum=5
23, sum=5          212, sum=5
32, sum=5          221, sum=5
41, sum=5          311, sum=5
15, sum=6          114, sum=6
 :    :             :     :
89, sum=17         989, sum=26
98, sum=17         998, sum=26
99, sum=18         999, sum=27

ソリューションは、まだ多少最適化することができることを覚えておいてください - 私は再帰がいかにエレガント示すために、その最初の形でそれを残しました。純粋な反復解法は、以下が、私はまだ再帰的なものを好むます。

次のプログラムを実行し、目的の順序を取得するために、UNIXの下sortawkを使用しています。たとえばます:

go | sort | awk '{print $2}'

これはソートを行うために外部ツールを使用することに注意してくださいしかし、あなたは同じように簡単にソートCのコード内(メモリが許す)可能性があります。

#include <stdio.h>

int main (void) {
    int i, sum, carry, size;
    int *pDigit;

    // Choose your desired size.

    size = 2;

    // Allocate and initialise digits.

    if ((pDigit = malloc (size * sizeof (int))) == NULL) {
        fprintf (stderr, "No memory\n");
        return 1;
    )

    for (i = 0; i < size; i++)
        pDigit[i] = 1;

    // Loop until overflow.

    carry = 0;
    while (carry != 1) {
        // Work out sum, then output it with number.
        // Line is sssssssssssssssssss ddddd
        //   where sss...sss is the fixed-width sum, zero padded on left (for sort)
        //   and ddd...ddd is the actual number.

        sum = 0;
        for (i = 0; i < size; i++)
            sum += pDigit[i];

        printf ("%020d ", sum);
        for (i = 0; i < size; i++)
            printf ("%d", pDigit[i]);
        printf ("\n");

        // Advance to next number.

        carry = 1;
        for (i = 0; i < size; i++) {
            pDigit[size-i-1] = pDigit[size-i-1] + carry;
            if (pDigit[size-i-1] == 10)
                pDigit[size-i-1] = 1;
            else
                carry = 0;
        }
    }

    return 0;
}

他のヒント

あなたが使用することはできますのstd :: next_permutation の?

  

next_permutation()関数   与えられた範囲を変換しようとします   次に要素[開始、終了)の   辞書順に大きい順列   要素の。それは、それを成功した場合   それは返し、そうでない場合は、trueを返します   偽ます。

     

厳しい弱い順序付け機能の場合   オブジェクトCMPが提供され、それが中で使用されています   <演算子の代わりに比較します   要素ます。

前のSOお答えする これを参照してください。 >
あなたはとても長いパターンが存在するとして使用しているもののパターンそれは問題ではない場合は、

のn = 3のために、あなたまで111と増分で始まり、その後(あなたが心の中で特定のパターンを持っているかどうか、それはあなたのポストから完全には明らかではありません) 999に達しています。

ところで、あなたが求めているもののため用語は、まさに「順列」ではありません。

あなたは2つのバケットにあなたの問題を軽減しようとすることができます:

二つのバケット分割が簡単である:Aは一つだけ含まれるまで、すべてのマイナスバケットA内の1つのバケットBの1から始めて、その後、Bへの1を置く

そしてちょうどされている3つのバケット分割:Aは一つだけ含まれるまで、BおよびCのいずれかによってAを削減し、BとCで3の全ての2つのバケット分割を集めるのすべてのマイナスバケツAに2つ、1それぞれで起動しますが、繰り返します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top