トピック:
整数のソートされていない配列を指定して、最長の増加部分列の長さを見つけます。
例:
入力:[10,9,2,5,3,7,101,18]
出力:4 説明:最長増加サブシーケンスであり[2,3,7,101]
、したがって、長さ4
。
注意:
- あなたは長さを返すことが必要なだけである、複数のLISの組み合わせがあるかもしれません。
- あなたのアルゴリズムはOで(実行する必要がありN2)の複雑さを。
フォローアップ:あなたはそれがOに改善できる(nは ログ nは時間の複雑さ)?
分析:
指定された整数配列の乱れ、最長見出さ立ち上がりシーケンスの長さ。
この場合は[2,3,4]連続で、我々はこのような問題を観察するために行くことができ、既知の配列は[16,17,2,3,4]その最大の上昇シーケンスがある。この問題は、立ち上がりシーケンスを必要としないことに注意してください20が来たとき、私たちは見て。
端部4との組み合わせ20と、この時点で私達の配列である[16,17,2,3,4,20]シーケンスの最大増加は[2,3,4,20]、すなわち最大長さ3 + 1 = 4(最大リフト端長で元の配列の配列は、4 + 1です)。
組み合わせで終了3~20場合、我々は[16,17,2,3,20】配列され、この時のシーケンスが最大立ち上がり[2,3,20]であり、最大長は2 + 1です。
、我々は[16,17,2,20]配列であり、この時のシーケンスが最大立ち上がり[2,20] 2及び20の端部の組み合わせである場合、最大長は1 + 1です。
あなたは最大の上昇配列は[16、17]すべきではない、この時点でそれを頼むかもしれませんか?我々は最後に2つのサブシーケンスの最大上昇を求めているこの時点で、我々は唯一の[2,20]することができ、覚えておいてください。
組み合わせにおける両端17及び20場合、我々はこの時点でシーケンス[16、17]配列が最大上昇[16、17]であり、最大長は2 + 1です。
組み合わせにおける両端16及び20場合、我々はこの時点でシーケンス[16、20]配列が最大上昇[16、20]であり、最大長は、1 + 1です。
私たちは、それぞれの新しい要素-反復を再し、新しい要素が現在の要素よりも大きい場合に比べて、それが現在の要素に新しい要素は、子で最大の増加で終わることができることを意味して以前のすべての要素に行くことができますシーケンスの最大増加の新しい配列、及び現在の要素で終わる長さの増加サブ+1最大上昇サブシーケンスに等しい新たな最大の長さは、一部は、入り組んだ音できるようになっています。我々は、新しい配列を作成し、元の配列のサイズと同じ大きさ、対応する位置は、この要素の最大立ち上がりサブシーケンスの長さが終了される格納します。
10 | |||||||
1 | |||||||
10 | 9 | ||||||
1 | 1 | ||||||
10 | 9 | 2 | |||||
1 | 1 | 1 | |||||
10 | 9 | 2 | 5 | ||||
1 | 1 | 1 | 2 | ||||
10 | 9 | 2 | 5 | 3 | |||
1 | 1 | 1 | 2 | 3 | |||
10 | 9 | 2 | 5 | 3 | 7 | ||
1 | 1 | 1 | 2 | 2 | 3 | ||
10 | 9 | 2 | 5 | 3 | 7 | 101 | |
1 | 1 | 1 | 2 | 2 | 3 | 4 | |
10 | 9 | 2 | 5 | 3 | 7 | 101 | 18 |
1 | 1 | 1 | 2 | 2 | 3 | 4 | 4 |
それぞれの新しい要素、および比較するためのシーケンスの最後に、各要素の前にする必要がありますが、新たな上昇シーケンスになることができます。時間計算量はO(N ^ 2)となるように、最終的に、アレイ内の最大値、長配列に、すなわち、最大の増加を返します。
今、私たちはO(nlogn)メソッド再びそれを見て、私たちは最も有望な上昇シーケンスの1を維持するために二分探索DPの配列を使用します。
私たちは、[..... 10,20,30,1,2,3]列ならば、それは順序で最大の増加をもたらすよりも1,2,3 10,20,30は、より有望なことは明らかであることを知っています。
[10,20,30,1,2,3,5]列の数を考えます。
まず10に、そして最も有望な上昇系列の時間は、DP:[10]。
20、DP:[10,20]
30、DP:[10,20,30]
この新しいで最も有望な上昇サブシーケンス[20、30]のこの時点では、10 1を交換します、バイナリ検索要素を使用して、ミックス1に追加し、あなたが戻っての30で、1を依頼し、ないかもしれません20及び30は、実際に、立ち上がりシーケンスを構成し、我々は最も有望であるために頼む、我々は後者がシーケンス内の大きな増加の要素を構成できない場合、配列のサイズは、次に、現在のシーケンスで最大の上昇の長さであります配列のサイズはまた、次のレコードの前のサブシーケンスの長さが最大の増加があり、この点については心配しないでください。
1、DP:[1,20,30]
2、DP:[1,2,30]
3、DP:[1,2,3]
5、DP:[1,2,3,5]
私たちは最も有望な上昇シーケンスを見つける何、この時点でDP、その長さは最大立ち上がりシーケンスの長さです。
シーケンスである場合は、[10,20,30,1,2]
DPは最後[1,2,30]を求めているであろうが、今回配列のサイズは、この立ち上がりシーケンスを構成しないが、それは前10、20から展開され、また、最大立ち上がりシーケンスを保持します長さ。
手順:
C ++
// 動的な クラスのソリューション{ パブリック: int型 lengthOfLIS(ベクトル< int型 >&NUMS){ 場合(nums.size()== 1)リターン 1 。 int型最長= 0 ; ベクター < INT > RES(nums.size()、1 )。 以下のために(int型私= 1 ; iが<(nums.sizeを); ++ i)が{ ため(INT J = I; J> 0 ; j-- ){ もし(NUMS [I]> NUMS [J- 1 ]){ RES [I] = MAX(RES [i]は、RES [J- 1 ] + 1 )。 } } } のための(自動N:RES){ 場合(N <最長)最長= N。 } 戻り最長。 } }。
// バイナリ検索とダイナミックプログラミング クラスのソリューション{ パブリック: int型 lengthOfLIS(ベクトル< int型 >&NUMS){ 場合(nums.size()== 0)の戻り 0 ; ベクトル < int型 > のres; res.push_back(NUMS [ 0 ])。 以下のために(int型 iは= 1 ; iはnums.sizeを()<; ++ I){ int型のインデックス= binarySearch(RES、NUMS [I])。 もしインデックス(== - 1) RES [ 0 ] = NUMS [I]。 そう であれば(インデックス< - 1 ) res.push_back(NUMS [I])。 他 のres [インデックス] = NUMS [i]は、 } 戻りres.size()。 } int型 binarySearch(ベクトル< INT >&V、INTのNUM){ 場合(NUM <V [ 0 ])のリターン - 1 。 もし(NUM> V [v.size() - 1 ])リターン - (v.size()+ 1 )。 int型L = 0 。 INT R = v.size() - 1 ; int型の半ば。 一方、(L <= R){ ミッド = 1 +(RL)/ 2 。 もし(NUM <V [中間])R =半ば1 。 そう であれば(NUM> V [中間])L =ミッド+ 1 。 他に 戻る途中に、 } 戻りL。 } }。
ジャワ
// バイナリ検索とダイナミックプログラミング クラスのソリューション{ 公共 のint lengthOfLIS(INT [] NUMS){ 場合(nums.length == 0)の戻り 0 ; int型 [] RES = 新しい int型[nums.length]を。 int型のサイズ= 0 ; 以下のために(int型、iはnums.lengthを<; I = 0 ++ I){ int型のインデックス= Arrays.binarySearch(RES、0 、サイズ、NUMS [I])。 もし(指数<0)指数= - (インデックス+ 1 )。 RES [インデックス] =NUMS [I]; IF(インデックス==サイズ)サイズ++ ; } 戻りサイズ; } } // ジャワbinarySearch // [1]検索キーの範囲が、アレイのない要素に、「与えるために、いずれかでカウントを開始-挿入ポイントインデックス値「; //は[2]検索キーの範囲、および配列要素の検索のインデックス値を得るために、ゼロカウント値から開始; // [3]検索キーの範囲内にない、未満(要素内の配列)、リターン- (+たfromIndex 1); // [4]キーは、探索範囲内にない、および要素(アレイ)、および戻りの範囲よりも大きい- (たtoIndex + 1)。