このコードは、バイナリツリーがバランスされている場合バランスは、任意のノードの2つのサブツリーの高さは、複数によって異なることがないように、ツリーのように定義されている(チェックすることを意味します。
私は、実行時のO(NlogN)のNの一部を理解しています。ツリー内のすべてのノードが少なくとも一度訪れているので、Nです。
int getHeight(TreeNode root){
if(root==null) return -1; //Base case
return Math.max(getHeight(root.left), getHeight(root.right))+1;
}
boolean isBalanced(TreeNode root){
if(root == null) return true; //Base case
int heightDiff = getHeight(root.left) - getHeight(root.right);
if(Math.abs(heightDiff) > 1){
return false;
} else{ //Recurse
return isBalanced(root.left) && isBalanced(root.right);
}
}
私は理解していないことは、ランタイムO(NlogN)のlogN個の部分です。コードは、ツリーの下にノードから可能なすべてのパスをトレースします。そのためのコードは、よりN2 ^ Nか何かのようにすべきですか?どのようにステップバイステップ1は、ランタイムはO(NlogN)であるという結論に来るのでしょうか?
このコードの実行時には(N Nログ)必ずしもOではないことを私はあなたに同意します。しかし、私はそれは常に、ツリーの下にノードからすべてのパスをトレースすることを信じていません。例えば、このツリーを考えてみます。
*
/
*
/
*
ここでは、左と右のサブツリーの深さを計算することは確かに一度、すべてのノードを訪問します。不均衡は、左と右のサブツリーの間で発見されたのでしかし、再帰は再帰的に左のサブツリーを模索せずに停止します。言い換えれば、再帰は多くの作業を行う必要があります例を見つけることは、いくつかの創造性を必要とする予定です。
あなたは、すべてのノードがスキャンされなければならないため、高低差のベースラインチェックは時間Θ(n)を取ることが正しいです。このコードの懸念は、それが再帰の間に高低差を再計算して、それは、ノード多く、何度も再スキャン可能性があるということです。しかし、長い時間のために、必ずしもできるだけ長く - - 私たちは、この機能は本当に長い時間のために実行したい場合は、私たちはそのためにそれを作りたいと思います
- 左と右のサブツリーを再帰左サブツリーに進むように、ほぼ同じ高さを有するが、
- 木は非常に左の部分木へのノードのほとんどを置く、アンバランスされます。
これを行う方法の1つは、右のサブツリーが左部分木としてではなく、道少ないノードと同じ高さにたまたまちょうど長い背骨である木を作成することです。ここでは、このプロパティを持つ木の一つの可能なシーケンスです:
*
/ \
* * *
/ \ / \ \
* * * * * *
/ \ / \ \ / \ \ \
* * * * * * * * * *
機械的には、各ツリーは前の木を取って、その上に右方向背骨を置くことによって形成されます。次のように操作上、これらの木を再帰的に定義されています。
- 注文0ツリーは、単一のノードです。
- order-(K + 1)ツリーは、その左の子および右側の子の高さkのリンクされたリストであるため、K木のノードです。
オーダーkのツリー内のノードの数は、Θ(Kであることに注意してください2)。あなたは木が各層が前のものよりも1つの以上のノードを持っている素敵な三角形の形状を、持っていることに気づいことで、これを見ることができます。Θ(kに出て、フォーム1 + 2 + 3 + ... + k個の作業の和2)、私たちはそこに、これよりもより正確になることができますが、本当にそうする必要はありません。
私たちはこれらの木のいずれかのルートに、この再帰をオフに解雇場合さて、何が起こりますか?まあ、再帰は、それらが互いに同じ高さを持っていることを報告します左と右のサブツリーの高さを計算することによって開始されます。その後、再帰的にそれはバランスが取れていますかどうかを確認するために左のサブツリーを探ります。作業の一部(大)量を行った後、それは再帰が右サブツリーに分岐しないであろう、その時点で、左の部分木がバランスされていないことがわかります。換言すれば、オーダーkのツリーに行われた作業の量によって低制限されます
- W(0)= 1 (回訪問単一のノードがあります)、および
- W(k + 1)= W(K)+Θ(K 2)。
W(K + 1)という用語は、通知、どこから来る我々はΘをツリー内のすべてのノードを走査することによって開始し、そこであることを確認するために(K 2)ノードは、次に、再帰的に左サブツリーに手順を適用し、スキャンします。この再発を展開する、我々はオーダーkのツリーで、合計作業が行われていることです見ます
W(k)=Θ(K 2)+ W(K-1)
=Θ(K 2 +(k - 1)2)+ W(K - 2)
=Θ(K 2 +(k - 1)2 +(K - 2)2)+ W(K - 3)
...
=Θ(K 2 +(k - 1)2 + ... + 2 2 + 1 2)
= TH(K 3)。
この最後のステップは、最初のk個のキューブの合計はΘ(kにうまくいくという事実から、以下の3)。
物事を締めくくるために、私たちは一歩を持っています。私たちは、オーダーkの木はΘ(k個必要であることが示されてきた3)この再帰アルゴリズムを持つプロセスへの総仕事を。しかし、私たちは、木の順序をK、Nの面で拘束ランタイム、ツリー内のノードの総数ではなくたいと思います。次数kのツリー内のノードの数は(KΘであるという事実使用2)、我々は、n個のノードを有するツリー順Θ(K持つことを参照1/2)。この中を差し込む、我々は任意の大きさnについて、我々は全仕事はΘに等しい行わせることができることがわかる((N 1/2)3)= Θ(N 3/2) Oを超え、(N Nログ)を提案あなたが言及した結合しました。私は確かに、これは、このアルゴリズムの最悪の場合の入力であるかないんだけど、それは確かに良いものではありません。
そうです、あなたは正しいです-ランタイムはO(N Nログ)一般的ではありません。しかし、それがある場合には、(N Nログ)ツリーは完全にバランスされている場合、ランタイムは確かにOであること。ツリーは完全にバランスされた場合に、各再帰呼び出しがする理由は、予告表示するには
- 次に、ツリー内の各ノードを走査O(n)の作業を行います
- 前のと同じ大きさの約半分であるそれぞれの小さな木の上に2つの再帰呼び出しを行います。
すなわち、再発T(N)= 2T(N / 2)+ O(N)、解くOへの(N Nログ)を得ます。しかし、それはただ一つの特定のケースではなく、一般的なケースです。
結びのノート-マイナーな修正で、このコードはすべてのケースで、時間はO(n)で実行させることができます。(深さまたは補助有すること等しいいくつかの内部フィールドを設定することにより、いずれかの代わりに、各ノードの深さを再計算により、ツリー上に最初のパスを作成し、その深さを有する各ノードに注釈を付けるHashMap
マッピングその深さに各ノード)。これは、時間O(N)で行うことができます。そこから、再帰的にツリーを歩いて、左と右の部分木が多くても1つのATによって異なる高さを有しているかどうかをチェックすることはO(1)の両端のノード当たりの仕事のn O(N)の合計実行時間の合計ノードを必要とします。
お役に立てれば!