(再帰なし)は、個々の数字の和によって配列のn桁の数字を生成します
-
19-09-2019 - |
質問
私は、シーケンスが、個々の数字の合計によって決定され、次の順序では、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
和グループ内の順序は重要ではありません。
すべてのヘルプ、アイデアをいただければ幸いです。
解決
あなたはは常には、反復一つに再帰的な問題を回すことができる - 再帰を避ける理由は、言語がそれをサポートしていないということであればそれはです。 P>
しかし、言語は、のないのそれをサポートする場合は、再帰的なソリューションは、はるかにエレガントされます。
私は再帰を避けるために考えることができる唯一の他の理由は、限られたスタックの深さです。その場合、再帰溶液の反復変換は、できるだけ多くのスタック空間を必要としないことで問題を緩和します。
しかし、あなたは処理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の下sort
とawk
を使用しています。たとえばます:
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 の?
前のSOお答えする これを参照してください。 >next_permutation()関数 与えられた範囲を変換しようとします 次に要素[開始、終了)の 辞書順に大きい順列 要素の。それは、それを成功した場合 それは返し、そうでない場合は、trueを返します 偽ます。
厳しい弱い順序付け機能の場合 オブジェクトCMPが提供され、それが中で使用されています <演算子の代わりに比較します 要素ます。
のn = 3のために、あなたまで111
と増分で始まり、その後(あなたが心の中で特定のパターンを持っているかどうか、それはあなたのポストから完全には明らかではありません) 999
に達しています。
ところで、あなたが求めているもののため用語は、まさに「順列」ではありません。
あなたは2つのバケットにあなたの問題を軽減しようとすることができます:
二つのバケット分割が簡単である:Aは一つだけ含まれるまで、すべてのマイナスバケットA内の1つのバケットBの1から始めて、その後、Bへの1を置く
。そしてちょうどされている3つのバケット分割:Aは一つだけ含まれるまで、BおよびCのいずれかによってAを削減し、BとCで3の全ての2つのバケット分割を集めるのすべてのマイナスバケツAに2つ、1それぞれで起動しますが、繰り返します。