生のバイナリ文字列の長さnのkビットセット
-
13-09-2019 - |
質問
どのアルゴリズムのすべてのバイナリ文字列の長さnを含むkビットです。例えば、n=4,k=3のある---
0111
1011
1101
1110
いをこれませk思うのです文字列です。
解決
この方法では、正確にN '1' ビットですべての整数を生成します。
https://graphics.stanford.edu/~seander/bithacks.htmlから#NextBitPermutationする
辞書次のビットの順列を計算
我々は整数で1に設定さNビットのパターンを持っていると我々はたいと 辞書式意味でN 1ビットの次の順列。ために 例えば、nが3であり、ビットパターンは、次のパターン
00010011
ある場合 、00010101
、00010110
、00011001
、00011010
、00011100
、00100011
だろう など。以下は、次を計算するための高速な方法です 順列ます。unsigned int v; // current permutation of bits unsigned int w; // next permutation of bits unsigned int t = v | (v - 1); // t gets v's least significant 0 bits set to 1 // Next set to 1 the most significant bit to change, // set to 0 the least significant ones, and add the necessary 1 bits. w = (t + 1) | (((~t & -~t) - 1) >> (__builtin_ctz(v) + 1));
のx86 CPUの固有
__builtin_ctz(v)
GNU Cコンパイラは、末尾のゼロの数を返します。あなたは、Microsoftのコンパイラを使用している場合 x86の、本質的には_BitScanForward
です。これらは両方bsf
を発します 命令が、同等物は、他のアーキテクチャのために利用可能であってもよいです。 そうでない場合には、カウントするための方法のいずれかを使用することを検討してください 前述の連続するゼロ・ビット。ここでは別のバージョンがあること 、その除算演算子で遅くなる傾向にあるが、それはしていません 末尾のゼロを数える必要があります。unsigned int t = (v | (v - 1)) + 1; w = t | ((((t & -t) / (v & -v)) >> 1) - 1);
2009年11月28日にこれを提供するアルゼンチンのダリオSneidermanis、おかげます。
他のヒント
Python
import itertools
def kbits(n, k):
result = []
for bits in itertools.combinations(range(n), k):
s = ['0'] * n
for bit in bits:
s[bit] = '1'
result.append(''.join(s))
return result
print kbits(4, 3)
Output: ['1110', '1101', '1011', '0111']
説明:
基本的に必要がありますの位置に1ビット.あるnお選びkの方法を選択kビットの中でnビット.itertoolsは素敵なモジュールはここです。itertools.組み合わせ(range(n),k)を選びまkビットから[0,1,2...n-1]およびそれをうかがわせるものとなっているビルの文字列に対するビスを作成します。
てんPythonを使用した、擬似コードitertools.組み合わせはこちら
http://docs.python.org/library/itertools.html#itertools.combinations
はめて使用言語を問いません。
忘れられている("で行文字列"は明らかに 実施 発行いたします!) --について考え アルゴリズム, で、ピートの日本酒---だけど、最初のタグです。
い求めているのは、すべての組み合わせK品のセットの指標の0-N-1のセットです。それも単純な表現を再帰的には、例えば、擬似コード:
combinations(K, setN):
if k > length(setN): return "no combinations possible"
if k == 0: return "empty combination"
# combinations INcluding the first item:
return (first-item-of setN) combined combinations(K-1, all-but-first-of setN)
union combinations(K-1, all-but-first-of setN)
すなわち、最初の項目は現在または欠席:存在する場合には、K-1左(ジェクトの最後尾から別名すべてのもの-dv),無い場合、K左ます。
パターンマッチング機能言語SMLやウで行われるこの擬似コード(手続きのものように、私の大好きPython、実際にマスクの問題も深くどすぎる豊富な機能、など itertools.combinations
, なすべてのハードできるようになりました隠す関す).
あけましておめでとうございま最も身近なり、この目的--、SML、,...?う意味になってasがどういう訳以上の擬似コードします。では言語など、ワニやPythonのようなものはもちろんですが、その点はご理を理解するこの宿題をする、こんなにも豊富な機能など itertools.combinations
, く再帰(再帰-消去、必要な場合)により明らかなプリミティブ(ヘッド、テール、連結).くださいましょうか擬似コード-言語だけが知って!(いう問題はい状態が同じであるequipotent"得るものすべての組み合わせの項目や範囲(N)"でした。).
このC#の方法は、すべての組み合わせを作成する列挙子を返します。それは組み合わせを作成するとして、あなたがそれらを列挙するとそれだけでスタック領域を使用していますので、それは、それが作成できる組み合わせの数にメモリ空間によって制限されていない。
これは私が思いついた最初のバージョンです。それは、およそ2700の長さにスタック空間によって制限されています:
static IEnumerable<string> BinStrings(int length, int bits) {
if (length == 1) {
yield return bits.ToString();
} else {
if (length > bits) {
foreach (string s in BinStrings(length - 1, bits)) {
yield return "0" + s;
}
}
if (bits > 0) {
foreach (string s in BinStrings(length - 1, bits - 1)) {
yield return "1" + s;
}
}
}
}
これは、最初の文字をオフに分割するのではなく、バイナリ分割を使用する第2のバージョンは、あるので、はるかに効率的にスタックを使用します。これは、唯一それが各反復で作成される文字列のためのメモリ空間によって制限されています、と私は10000000の長さにそれをテストしています:
static IEnumerable<string> BinStrings(int length, int bits) {
if (length == 1) {
yield return bits.ToString();
} else {
int first = length / 2;
int last = length - first;
int low = Math.Max(0, bits - last);
int high = Math.Min(bits, first);
for (int i = low; i <= high; i++) {
foreach (string f in BinStrings(first, i)) {
foreach (string l in BinStrings(last, bits - i)) {
yield return f + l;
}
}
}
}
}
一つの問題の多くは標準的なソリューションにこの問題の全体セットの文字列が生成され、その後は反復による排気のスタックです。められなかったのでうれしいですが扱害が最小のセット。また、多くの場合、一部サンプリングが必要なのが、標準の(再帰的ソリューション一般にchopの問題を作ることは大きく偏った一方向に(例えば.を考慮に入れたソリューションがゼロに始まって後は全てのサービスの一つの開始)。
多くの場合入するのではなく、desireableることに大きなビット文字列を指定して要素の選択を機能として返しますが次のビット文字列にして最小限の変更(このとして知られておりグレード)として表現したのです。
Donald Knuthカバー全体ホストのアルゴリズムのためには彼の名前の由来3A,部7.2.1.3:発生すべての組み合わせとなります。
あのアプローチのための取り組みを繰り返しグレードアルゴリズムのためのすべての方法を選択k要素からn http://answers.yahoo.com/question/index?qid=20081208224633AA0gdMl リンク最終のPHPコードのコメント(クリックで拡大)下部のページです。
動作するはず1つのアルゴリズムます:
generate-strings(prefix, len, numBits) -> String:
if (len == 0):
print prefix
return
if (len == numBits):
print prefix + (len x "1")
generate-strings(prefix + "0", len-1, numBits)
generate-strings(prefix + "1", len-1, numBits)
グッドラック!
より一般的な方法では、以下の機能がNのために可能なすべてのインデックスの組み合わせを使用すると、その文字列または任意の他に適用することができKの問題を選択し、あなたを与えるだろう。
def generate_index_combinations(n, k):
possible_combinations = []
def walk(current_index, indexes_so_far=None):
indexes_so_far = indexes_so_far or []
if len(indexes_so_far) == k:
indexes_so_far = tuple(indexes_so_far)
possible_combinations.append(indexes_so_far)
return
if current_index == n:
return
walk(current_index + 1, indexes_so_far + [current_index])
walk(current_index + 1, indexes_so_far)
if k == 0:
return []
walk(0)
return possible_combinations
することを可能とし1.5-ライナー:
$ python -c 'import itertools; \
print set([ n for n in itertools.permutations("0111", 4)])'
set([('1', '1', '1', '0'), ('0', '1', '1', '1'), ..., ('1', '0', '1', '1')])
..場所 k
の数 1
s "0111"
.
のitertoolsモジュールの説明及びその方法に相当する 換方法.
私は、再帰をしようとするだろう。
それらの1のkのn桁があります。これを表示する別の方法は、それらの間で分散N-k個の0と、K + 1つのスロットのシーケンスです。すなわち、k回(1続く0のラン)は、次いで0の別の実行が続きます。これらの実験のいずれも長さがゼロであることができるが、全体の長さは、N-Kである必要がある。
K + 1つの整数の配列としてこれを表現。再帰の下部にある文字列に変換します。
再帰的深さn-K、再帰呼び出し前にアレイの一つの要素をインクリメントし、それをデクリメント方法、K + 1回呼び出す。
N-K、出力列の深さ。
int[] run = new int[k+1];
void recur(int depth) {
if(depth == 0){
output();
return;
}
for(int i = 0; i < k + 1; ++i){
++run[i];
recur(depth - 1);
--run[i];
}
public static void main(string[] arrrgghhs) {
recur(n - k);
}
私は、Javaを行っているので、しばらくしているので、このコードでは、おそらく若干の誤差がありますが、アイデアは動作するはずです。
は、intの配列よりも速く文字列はありますか?文字列に先頭に追加すべてのソリューションは、おそらく各反復での文字列のコピーになります。
だから、おそらく最も効率的な方法は、あなたがに追加intやcharの配列になります。 Javaは右、効率的な成長可能コンテナを持っていますか?それは文字列よりも高速だなら、それを使用してください。 BigIntegerのが効率的である場合、各ビットはビットのみ、全体ではなく、バイトまたはINTがかかるためか、それは、確かにコンパクトです。しかし、その後、あなたがビットをマスクし、&、および次のビット位置にマスクをビットシフトする必要があるビットを反復処理します。 JITコンパイラは、これらの日というのが得意でない限り、だから、おそらく遅くなります。
私は、元の質問にこのコメントを投稿するだろうが、私のカルマは十分に高くありません。申し訳ありません。
パイソン(機能的なスタイル)
あなたが私たちのpython
のitertools.combinations
のすべての選択肢を生成し、k
でバイナリ配列にそれらの選択肢をマッピングすることができn
のreduce
を使用して
from itertools import combinations
from functools import reduce # not necessary in python 2.x
def k_bits_on(k,n):
one_at = lambda v,i:v[:i]+[1]+v[i+1:]
return [tuple(reduce(one_at,c,[0]*n)) for c in combinations(range(n),k)]
使用例:
In [4]: k_bits_on(2,5)
Out[4]:
[(0, 0, 0, 1, 1),
(0, 0, 1, 0, 1),
(0, 0, 1, 1, 0),
(0, 1, 0, 0, 1),
(0, 1, 0, 1, 0),
(0, 1, 1, 0, 0),
(1, 0, 0, 0, 1),
(1, 0, 0, 1, 0),
(1, 0, 1, 0, 0),
(1, 1, 0, 0, 0)]
さて /このの重複としてマークされているA>質問(あなたが設定ビットの彼らの数の増加ために、すべてのサブマスクを反復処理する必要がある場合)、ます。
私たちは、単純に、設定されたビット数に応じて、すべてのサブマスクは、ベクトルに追加反復処理し、それを並べ替えることができます。
vector<int> v;
for(ll i=mask;i>0;i=(i-1)&mask)
v.push_back(i);
auto cmp = [](const auto &a, const auto &b){
return __builtin_popcountll(a) < __builtin_popcountll(b);
}
v.sort(v.begin(), v.end(), cmp);
別の方法は、すべてのサブマスクN回以上反復し、設定されたビット数がi番目の反復でIに等しい場合、ベクターに番号を追加することであろう。
の両方の方法はO(N * 2 ^ N)の複雑さを有する