アレイ与え
nums
、すべての移動する機能を記述し0
、非ゼロの要素の相対的な順序を維持しながら、それの最後に「秒。例:
入力:[0,1,0,3,12]
出力:[1,3,12,0,0]
注意:
- あなたは、配列のコピーを作成することなく、その場でこれを行う必要があります。
- 操作の合計数を最小限にします。
VaRの moveZeroes = 関数(NUMS)は{ POSせ = 0 。 // すべての非ゼロの維持 のために(聞かせて私は= 0; I <nums.lengthを; I ++ ){ 場合(!NUMS [I] == 0 ){ NUMS [POS ++] = NUMS [i]は、 } } // 全てゼロ数字追加 するための(; I <nums.length I ++ iはPOSを=せ{) NUMS [POS ++] = 0 ; } }。
このアプローチは、上記の、すなわち、最初に満たし1つの要件とし、別のと同じように動作します。キャッチ?これは巧妙な方法でそれをしません。上記の問題は、「同一のそれらの相対的な順序を維持アレイの前にすべての非0の要素を持参」、別の方法で述べることができます。
これは、2ポインタのアプローチです。変数「CUR」で示されている高速のポインタは、新しい要素を処理する仕事をしていません。新たに見つかった要素が0でない場合、私たちは最後FOUND非0要素の後にそれを記録します。最後FOUND非0の要素の位置が遅いポインタ「lastNonZeroFoundAt」変数によって示されます。我々は新たな非0要素を見つけておくように、我々は単に「lastNonZeroFoundAt + 1」番目のインデックスでそれらを上書きします。我々はすでにそこにあったものを加工しているため、この上書きは、(それが非0であれば、それはもう今で書かれているインデックスを、対応するだ、またはそれが0であれば、それは時間の後半で処理される)データの損失にはなりません。
「CUR」インデックスが配列の最後に到達した後、我々は今、すべての非0要素が元の順序に配列の先頭に移動されていることを知っています。今、他の要件を満たすための時間が来る、「全て0のは、末尾に移動します」。私たちは今、単に0で「lastNonZeroFoundAt」インデックスの後にすべてのインデックスを入力する必要があります。
複雑性分析
スペース複雑さ: O(1)O (1 )。唯一の一定のスペースが使用されています。
時間計算: O(n)を。しかし、操作の総数は依然として次善です。合計操作(配列書き込み)コードがないことである N 、N(要素の総数)。
VaRの moveZeroesは= 関数(NUMSは){ // すべての非ゼロの維持 のために(私は0 =せ、POS = 0; I <nums.length; I ++ ){ 場合(!NUMS [I] == 0 ){ [NUMS [POS]、NUMS [I] = [NUMS [i]は、NUMS [POS]。 POS ++ } } };
以前のアプローチの操作の総数は、サブ最適です。例えば、すべての(最後を除く)先行ゼロ有するアレイ:アレイに[0、0、0、...、0、1] .How多くの書き込み操作を?以前のアプローチの場合は、0の書き込み のn-1 のn - 1回、必要ありません。私たちは、代わりに一度だけ書かれている可能性があります。どうやって?.....唯一の非0要素、すなわち、1を固定すること。
最適なアプローチは、再び上記溶液の微妙な拡張です。現在の要素が最高で、その正しい位置缶がそれの現在位置または位置以前も、非0であれば簡単に実現です。それは後者の一つだ場合、現在位置は、最終的には非0で占有される、または「CUR」インデックスより、インデックス大きい時0、その嘘。私たちは、以前のソリューションとは異なり、我々は次の反復でここに戻ってくる必要がないのでことを、すぐに0で現在位置を埋めます。
言い換えれば、コードは以下の不変を維持します。
遅いポインタ(lastNonZeroFoundAt)の前にすべての要素が非ゼロです。
現在のと遅いポインタ間のすべての要素がゼロです。
我々は非零要素に遭遇したときしたがって、我々は、両方のポインタを進め、現在及び遅いポインタによって指し示さスワップエレメントに必要。それはゼロ要素だ場合、私たちは現在のポインタを進めます。
インプレースこの不変で、それはアルゴリズムが動作することを確認するのは簡単です。
それは二つのポインタ、forループによって増加している「I」1つのポインタを維持する方法をkownための素晴らしい方法である、別のポインタ「POSは」もし(NUMS [I]!= 0)である、条件によって増加します。