この問題は、(1) 数字の配列のすべてのサブシーケンスを見つける、(2) 整数を数字にパックおよびアンパックするという 2 つのタスクに分けることができます。
array のサブシーケンスを考えてみましょう{a, b, c}
。配列を左から右にたどって生成し、2 つのパス (現在の要素をサブシーケンスに含めるパスと含めないパス) をたどることで、それらを生成できます。
これは、ツリーとして表すことができる再帰的なアプローチにつながります。
{}
/ \
{} {a}
/ \ / \
{} {b} {a} {ab}
/ \ / \ / \ / \
{} {c} {b} {bc} {a} {ac} {ab} {abc}
左に分岐すると現在の要素をスキップし、右に分岐するとその要素を含めます。要素自体はツリーの深さです。最初のレベルでは要素を扱い、次のレベルa
とb
最後のレベルでは要素を扱いますc
。
一番下の行にはすべてのサブシーケンスがあります。これには、不要な空のシーケンスと完全なシーケンスが含まれます。しかし、今のところそれらを含めましょう。(一番下の行の配列は、通常、べき乗集合と呼ばれます。これは、Web で検索可能な便利な用語です。)
再帰関数を伴う再帰について言及しましたが、関数はアウトです。
したがって、別の方法で問題に取り組む必要があります。木を横向きにしましょう。ダッシュは、要素がスキップされたことを示します。右側の表記は別の表記を使用しています:0
要素がスキップされたことを1
意味し、要素が含まれたことを意味します:
- - - 000
- - c 001
- b - 010
- b c 011
a - - 100
a - c 101
a b - 110
a b c 111
右のコードに見覚えがあるといいのですが、これは から000
まで111
を 2 進数で数える方法です。これは、要素を列挙する良い方法です。ここで、各数値でどのビットが設定されているかを知る方法が必要です。
数が奇数の場合、右端のビットが設定されます。他のビットについては、数値を 2 で繰り返し割ることによって確認できます。これは、2 進法では右にシフトし、右端のビットを破棄します。
元の数字から数字を抽出する方法は?その数は 10 進数です。ビット 0 と 1 は 2 進数であるため、2 進数のビットを見つけるのと同じアプローチを使用できます。
番号から始めます。最後の桁は、10 で割った余りをとった結果です。次に、数値がゼロになるまで 10 で割ります。このコードは、右から左に数字を生成します。ビットを見つけるためのコードもそうです。つまり、ビットが設定されているかどうかと、単一のループで出力する桁を見つけ、常に右端のビットを取得し、設定されている場合は元の数値の右端の数字を出力します。
空のサブシーケンスと完全なサブシーケンスは、列挙の最初と最後の項目です。不要な場合はスキップしてください。
数字に数字が繰り返されている場合、重複したサブシーケンスの問題が残ります。とにかくサブシーケンスを作成し、後でそれがすでに印刷されているかどうかを確認するというuser3629249の提案を除いて、これを解決する簡単な方法はわかりません。
これを行う簡単な方法は、サブシーケンスの配列を保持することです。その配列にはmax
エントリがあります。その配列を埋めたら、並べ替えてから出力しますが、前のエントリと等しいエントリはスキップします。
元の数値を毎回分解する必要がないように、数字の配列を使用する実装例を次に示します。qsort
のソート関数を使用しますが<stdlib.h>
、これにはソート関数が必要です。
#include <stdlib.h>
#include <stdio.h>
#define NUM 412131
typedef unsigned int uint;
int uintcmp(const void *pa, const void *pb)
{
const uint *a = pa;
const uint *b = pb;
return (*a > *b) - (*a < *b);
}
int main(void)
{
uint digit[20]; // array of digits
size_t ndigit = 0; // length of array
uint num = NUM;
uint max = 1;
size_t i;
while (num) {
digit[ndigit++] = num % 10;
num /= 10;
max *= 2;
}
uint res[max]; // array of subsequences
for (i = 0; i < max; i++) {
uint mask = i; // mask for bit detection
uint j = ndigit; // index into digit array
uint s = 0;
while (j--) {
if (mask % 2) s = s*10 + digit[j];
mask /= 2;
}
res[i] = s;
}
qsort(res, max, sizeof(*res), uintcmp);
for (i = 1; i < max - 1; i++) {
if (res[i] != res[i - 1]) printf("%u\n", res[i]);
}
return 0;
}