私は反復的な解決策を知っています:
与えられたn
要素のセット
を保存し、int v = 2^n
これまでのすべてのバイナリ番号を生成しますv
。
しかし、n> 32の場合はどうなるでしょうか?
すでに2^32のサブセットであることは知っていますが、それでも-32要素の制限を回避する方法は何ですか?
64アイテムの制限に満足している場合は、を使用できますlong
。
s/ sArrayList
の配列/ 。次のような関数があります。int
long
next
bool next(uint[] arr)
for (int i = 0; i < arr.length; i++)
if (arr[i] == 2^n-1) // 11111 -> 00000
arr[i] = 0
else
arr[i]++
return true
return false // reached the end -> there is no next
BitArray。おそらく、上記と比較してあまり効率的なオプションではありません。
next
最下位ビットを0から1に設定し、残りのすべてのビットを0に設定する関数を使用できます。例:
10010 -> 10011
10011 -> 10100
注-サブセットが非常に多いという理由だけで、これにはおそらく永遠に時間がかかりますが、それは問題ではありません。
この簡潔なHaskell実装のアナログを書くことができます:
powerSet = filterM (const [True, False])
filterM
C#に組み込みがないことを除いて。それは問題ありません、あなたはそれを自分で実装することができます。これが私の試みです:
public static IEnumerable<IEnumerable<T>> PowerSet<T>(IEnumerable<T> els)
{
return FilterM(_ => new[] {true, false}, els);
}
public static IEnumerable<IEnumerable<T>> FilterM<T>(
Func<T, IEnumerable<bool>> p,
IEnumerable<T> els)
{
var en = els.GetEnumerator();
if (!en.MoveNext())
{
yield return Enumerable.Empty<T>();
yield break;
}
T el = en.Current;
IEnumerable<T> tail = els.Skip(1);
foreach (var x in
from flg in p(el)
from ys in FilterM(p, tail)
select flg ? new[] { el }.Concat(ys) : ys)
{
yield return x;
}
}
そして、次のように使用できます。
foreach (IEnumerable<int> subset in PowerSet(new [] { 1, 2, 3, 4 }))
{
Console.WriteLine("'{0}'", string.Join(",", subset));
}
ご覧のとおり、実装のどこでも明示的に使用されているint
わけでも、明示的に使用されているわけでもないlong
ため、ここでの実際の制限は、現在のスタックサイズ制限で到達可能な最大再帰深度です。
UPD: Rosettaコードは非再帰的な実装を提供します:
public static IEnumerable<IEnumerable<T>> GetPowerSet<T>(IEnumerable<T> input)
{
var seed = new List<IEnumerable<T>>() { Enumerable.Empty<T>() }
as IEnumerable<IEnumerable<T>>;
return input.Aggregate(seed, (a, b) =>
a.Concat(a.Select(x => x.Concat(new List<T> { b }))));
}
次の方法でキャリービットを伝播することにより、@ biziclopアプローチを使用できます。長さKの32ビット「桁」のベクトルとして数値を格納します。したがって、2 ^(K * 32)サブセットとすべての増分を生成できます。操作は最大でO(K)操作を行います。私が考えることができるもう1つのことは、1つの配列にすべてのサブセットを生成する再帰的なバックトラックです。