どのようにして、0と1の数が等しいすべてのバイナリシーケンスを効率的に生成しますか?


10

バイナリシーケンスの長さだけ順序付けられたシーケンスである各ようにのいずれかであるまたは。このようなすべてのバイナリシーケンスを生成するには、次の方法で明らかなバイナリツリー構造を使用できます。ルートは「空」ですが、左の子はそれぞれ既存の文字列にを追加し、右の子を追加し。ここで、各バイナリシーケンスは、ルートで始まり、リーフで終わる長さパスです。x 1x n x j 0 1 0 1 n + 1nx1,,xnxj0101n+1

これが私の質問です:

正確にゼロと 1 を持つ、長さすべてのバイナリ文字列のみを生成したい場合は、もっと良いことはありますか?n n2nnn

「もっと上手くできるか」ということは、最初に上のツリー全体を構築し、次に「左」と「右」のエッジの数が等しいパスを見つけようとする愚かなアルゴリズムよりも複雑さを低くする必要があることを意味します。


1から範囲の数値の厳密に増加するシーケンスをすべて効率的に生成する方法を見つけることができますか?2 nn2n
Corneliusブランド

複雑さについてコメントすることはできませんが、私の単純なアルゴリズムでは、一種のバックトラックスキームを使用して、正方形のグリッドのエッジに沿って、1つのコーナーから斜めのコーナーまでの歩行を生成します。つまり、01と10は(ツリーとは異なり)同じ位置に配置されますが、バックトラックを使用すると、この履歴がわかります。
Hendrik Jan

おそらく別の注記として、ここに -iteratorの Java実装があり。(nk)
PAL GD

回答:


6

明らかに、長さバイナリ文字列があります。バイナリをトラバースするには、アルゴリズムは各ノードに1回アクセスする必要があります。つまり、 ステップ。4n2n

i=02n2i=22n+11=O(4n)

説明したツリーを走査するが、途中で1と0の数を数える再帰アルゴリズムを考えてみましょう。つまり、ツリーの適切な部分のみを走査します。
しかし、 0と 1を持つバイナリ文字列はいくつありますか?長さ文字列として 1 を選択し、ステップ2でスターリングの公式を使用し。 nnn2n

(2nn)=(2n)!(n!)2=4nπn(1+O(1/n))

編集
Peter Shorのコメントのおかげで、1と0をカウントする2番目のアルゴリズムで必要なステップ数も分析できます。私は彼のコメントを下から引用しています:

正確に 0と 1を持つすべてのバイナリシーケンスを見つけたいと考えています。各ノードが最大で 0と1のシーケンスであるバイナリツリーをトラバースします。 0 を超えるノードや 1 を超えるノードにアクセスする必要はありません。いくつのノードにアクセスする必要がありますか?ありと文字列 0と 1つのを。これをすべての合計するとは。ここで、ノードごとに一定の平均コストでこれらの各ノードにアクセスする必要があります。これを行うには、最初に左の子を訪問し、次に右の子を訪問します。nn2nnn(i+ji)iji,jni=0nj=0n(i+ji)=(2n+2n+1)1

スターリングの公式を再び使用して、 を新しいアルゴリズムの実行時間として。

(2n+2n+1)1=4n+11n+1(1+O(1/n))1=O(4nn)

あなたはもう少し注意する必要があります。おそらく各文字列を生成した後、それを時間で処理します。したがって、すべてのバランスのとれた文字列を処理するだけでは、時間がかかります。最適化された「ばかげた」生成アルゴリズムが確かにである場合、バグの機会以外に、よりスマートなアルゴリズムに切り替えることで得られることは何もありません。Ω(n)Ω(4nn)O(4n)
Yuval Filmus 2013年

@Yuval Filmus:「文字列処理」とはどういう意味ですか?出力に費やされた時間確かにを意味する場合は、その要素を "愚かな"アルゴリズムの実行時間でも考慮する必要があります。Θ(n)O(4nn)
tranisstor 2013年

2
私の要点は、との違いに関心がある場合は、少なくとも正しい実行時間を指定する必要があるということです。、2つのアルゴリズムの潜在的な違いを明らかにするには不十分です。さらに、提案された新しいアルゴリズムを慎重に分析する必要があります。これらの「無視できる」小さな要因によって、自明なアルゴリズムよりも遅くならないことを確認してください。4n4n/nO~(4n)
Yuval Filmus 2013年

2
「悪い部分」も含めずに、ツリーの「良い部分」だけを構築するにはどうすればよいですか?あなたはより多くの必要はありませんツリーのすべてのノード含める必要が左のお子様、それらへのルートからのパスに右の子供を。これは機能しますが、機能することを示すために追加の引数が必要です。具体的には、式を使用する必要があり。nni=0nj=0n(i+ji)=(2n+2n+1)1
Peter Shor 2013年

2
正確に 0と 1を持つすべてのバイナリシーケンスを見つけたいと考えています。各ノードが最大で 0と1のシーケンスであるバイナリツリーをトラバースします。 0 を超えるノードや 1 を超えるノードにアクセスする必要はありません。いくつのノードにアクセスする必要がありますか?ありを含む文字列 0と 1つの。これをすべてのに対して合計するとによって。ここで、ノードごとに一定の平均コストでこれらの各ノードにアクセスする必要があります。これを行うには、最初に左の子を訪問し、次に右の子を訪問します。nn2nnn(i+ji)iji,jni=0nj=0n(i+ji)=(2n+2n+1)1
Peter Shor 2013年

2

おそらく、私は厚めのものだけど、元の質問には、ツリートラバースするよりも効率的であった長さ2nの全ての「バランス」のバイナリシーケンスを生成する方法を求めて、すべてのバランスが取れたものを長さ2nのバイナリ列をのみ出力を。では、なぜ木を使用するのでしょうか。

このようなシーケンスをすべて生成する再帰アルゴリズムの擬似コードを次に示します(キーワード "yield"はシーケンスを出力に送信します):

function all-balanced(n) {
  all-specified( "", n, n );
};

function all-specified( currentString, zeroes, ones ) {

  if (zeroes == 0) {
    for i = 0 to ones {
      currentString += "1";
    };
    yield currentString;
    return;
  };

  if (ones == 0) {
    for i = 0 to zeroes {
      currentString += "0";
    };
    yield currentString;
    return;
  };

  all-specified( currentString+"0", zeroes-1, ones );
  all-specified( currentString+"1", zeroes, ones-1 );
  return;
};

何か誤解している場合は教えてください。ツリーの使用を指定していない、実際に発生した問題に対する最も効率的な回答のようです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.