説明原題:
アレイNUMS N含む整数与えられ、それは、3つの要素例えば+ B + C = 0つまり、B、CのNUMSが存在するか否かを判断しますか?すべての条件が重複したトリプルを見つけることは満足していません。
注:答えは重複したトリプルを含めることはできません。
例えば、アレイNUMS所与= [-1、0、1、2、-1、-4]
会うようにトリプルの設定要件:
[-1、0、1]、[ - 1、-1、2]]
オリジナルタイトルリンクします。https://leetcode-cn.com/problems/3sum
解決策1:解決するためのHashMapに基づく暴力
参考電源ボタンの問題:https://leetcode-cn.com/problems/two-sum/
最初の3カウントを固定し、その後、残りの2つの数字が一回横断することができます。時間計算量は$ O \左(\ mathrm {N} ^ {2} \右)$であるべきです
アドオン二つの数字との問題とは異なり、現在の困難な問題は、すべての組み合わせが必要な出力は、そこにある。しかし、重複を避ける必要があります
私の最初のアイデアは、にしました
- 条件を満たすために3つのデジタルを探します。
- 配置された3つの数。
- 文字列に変換された3の組み合わせの数。
- コンテナに格納します。
- 容器の特性によってスクリーニング。
最初のステップ:の部分を見つけるためには、HashMapのが宣言maptwo番号を見つけるために使用される、私は固定数2の後に休息を。
コード(参照符号)の一部として次の
1 のための(INT ; J <nums.length、J ++ J = I + 1 ){ 2 INTの目標=和- NUMS [J]。 3 であれば(maptwo.containsKey(ターゲット)){ // 和を判定するため使用される 4 int型 K = maptwo.get(ターゲット)。 5 sumlist.add(新規のArrayList <整数> (は、Arrays.asList(NUMS [I]、NUMS [J]、NUMS [K])))。 6 } 7 maptwo.put(NUMS [j]は、j)は、 8 }
ステップ:配列部分に、直接配列オブジェクトソート機能を使用して構築
INT [] newnums = {NUMS [i]は、NUMS [K]、NUMS [J]}。 Arrays.sort(newnums)。
その理由をソートすると、$ -101 -110 $ $ $を防ぐためのものですので、異なる文字列型変数から見て、実際の状況は同じです。
初めに、私は後者を再度ソートする必要はありません。入力配列、最初の並べ替えを取得することにしようとしていることに留意することができます。しかし、その後、デバッガ、および私たちはHashMapのの酒として、3つの数列はまだ変更を取得することがわかりました。たとえば、$ 1、0 $を検索する際に、最初もののためのアルゴリズムの$ 0 $を見つけるだろうが、今回は数が格納されmaptwoあなたは$ 1 $を見つけるまで、ない最後の記憶。このときNUMS [j]は $ 1 $であるべきで、NUMS [k]は並べ替えが必要とされ、$ 0 $です。
第三ステップ:数は、文字列を満たすに変換され、三つの条件
アレイを動的に追加することができるように、本明細書で使用されるデータタイプは、StringBufferのです。
sb.append(String.valueOf(newnums [0])); sb.append(String.valueOf(newnums [1]))。 sb.append(String.valueOf(newnums [2]))。
場所を追加します。私は、各要素の開始位置を追加することを選択する第二のラインと線分上のようなコードを追加した。3 NUMS [J]は、行を追加する。4 NUMS [K] 。ノートに問題があります:あなたは本当に第三の数が表示さの条件を満たしている場合には、第二およびすべての数字の数のようになります3番目の数字の間NUMS [J]のStringBufferに追加されます。例えば、所与のアレイ$ -2、-1、-1,0,1,3 $ため、すべての数字は、1,3 $ $組成物中にあるで添加されます。したがって、確認応答と第3の数の後に文字列変換操作に追加されるべきです。
第四のステップ&&ステップ5:貯蔵容器とフィルタ
HashMapのは、宣言mapall文字列情報を格納し、スクリーニングするための責任を負います。コードは以下の通りであります:
IF(mapall.containsValue(sb.toString())!){ //繰り返すか否かを判定するために使用 mapall.put(++ H、sb.toString())。 // SBのStringBufferの一種である }
SB =新規のStringBuffer();
その後、私は、実際には、HashMapを使用する必要が気づいていません。
ここでは、スクリーニング機能の両方のために、3個の組み合わせのすべての最後のストレージは、このコードに包まれなければなりません。また、StringBufferのは、HashMapの中に格納された後に解放されなければなりません。
以下は、完全なコードです:
1つの 公共のArrayList <のArrayList <整数>> threeSum(INT [] NUMS){ 2 であれば(nums.length <3 || NUMS == NULL ){ 3 リターン ヌル。 4 } 5 6 のArrayList <のArrayList <整数>> sumlist = 新しいArrayListを()。 7 8 のHashMap <整数、文字列> mapall = 新規のHashMap <整数、文字列> (); 9 INTの H = 0 。 10 11 のために(INT iは= 0; I <nums.length -1; I ++ ){ 12 //2つの要素を左側の検索NUMSために使用される 13 のHashMap <整数、整数> maptwo = 新規のHashMap <整数、整数> (); 14 //の繰り返しの組み合わせを比較するために使用される 15 のStringBuffer SB = 新規のStringBuffer(); 16 17 INTの和= 0- NUMS [I]。 18 のために(INT ; J <nums.length、J ++ J = I + 1 ){ 19 のintターゲット=和- NUMS [J]。 20 であれば(maptwo.containsKey(ターゲット)){ // 合計を判定するために使用 21 int型 K = maptwo.get(ターゲット) 22 23 のint [] newnums = {NUMS [i]は、NUMS [K]、NUMS [J]}。 24 は、Arrays.sort(newnums)。 25 sb.append(String.valueOf(newnums [0 ])); 26 sb.append(String.valueOf(newnums [1 ]))。 27 sb.append(String.valueOf(newnums [2 ]))。 28 29 もし(!mapall.containsValue(sb.toString())){ // 判断するために使用するかどうか繰り返さ 30 sumlist.add(新しいのArrayList <Integer型>(は、Arrays.asList(NUMS [I]、NUMS [J]、NUMS [K])))。 31 mapall.put(H ++ 、sb.toString())。 32 } 33 SBは= 新しいStringBufferの(); 34 } 35 maptwo.put(NUMS [j]は、j)は、 36 } 37 } 38 リターンsumlist。 39 }
ソリューションの時間の最終的な敗北で。。。
対処方法2:ダブルポインタ
時間の複雑さ、均一な溶液と解決策を述べました。また、あなたは(実際には、解決策は、ソートする必要はないかもしれない?)ソートする必要があります
原理は左端の桁が固定ということです。2つの数のスペースを横断するように、残りの値。各領域の両端に2つの番号、L及びR&LT。
以下のための道を横断
$ \ operatorname {和} = NUMS [I] + NUMS [L] + NUMS [R] \ \左{\開始{アレイ} {1} {0、\テキスト{行わ}} \\ {> 0、R - } \\ {<0、L ++} \端{アレイ} \右$。
図示のように
三つの値を発見した後、同様にして溶液と格納された値を使用して、条件を満たし
そして、この方法を防ぐ複製、
$ \ operatorname {NUMS} [L] == \ operatorname {NUMS} [L ++] $、$ L ++ $場合、ため。図の時間は、その結果は、左端が最大角度スケール(スキップされた左の数)を選択し、重複する値に遭遇し、そして省略する。
コードは、として実装しました
一方、(L <R && NUMS [L] == NUMS [L + 1])L ++。
同様に、$ \ operatorname {NUMS} [R - ]場合== \ operatorname {NUMS} [R]は$、$ R - $場合、示されているようなので、遭遇の右の数は重複する値すなわち、最小の添字を選択(スキップ右の数)、およびは省略する。
コードは、として実装しました
(L <R && NUMS [R] == NUMS [R-1])r--の一方。
2つの問題があることに留意すべきです。
- 2行のコードは、そうでない場合は、ソリューションを失われますスキップ、3つのデジタルプラスと会う要件の場合に確認すべきです。
- 確認サイクル決意条件見逃さないことL <R&LTを(ループ条件が第二層の周期です)。反例は、配列の境界まで成長します$ L $ $ $ -2,1,1,1,1、この方法、です。
ループの反復の後の最初の層です。去ったとき、同じ原則と価値を繰り返しを防ぐこと、ここで注意してください。私は、コードを書いていたちょうどその時、境界条件が閉じ込められています。全体のコードを与えることをここに:
1つの 公共のArrayList <のArrayList <整数>> newSolution(INT [] NUMS){ 2 のArrayList <のArrayList <整数>> sumlist = 新しいArrayListを()。 3 4 もし(nums.length <3 || NUMS == NULL ){ 5 リターンsumlist。 6 } 7 8 は、Arrays.sort(NUMS)。 9 10 INT iは0、L = I + 1、R = nums.lengthを= - 1 。 11 一方(I <nums.length && NUMS [i]が<= 0 ){ 12 ながら(L < R){ 13 、INT和= NUMS [I] + NUMS [L] + NUMS [R]。 14 であれば(和== 0 ){ 15 sumlist.add(新規のArrayList <整数> (は、Arrays.asList(NUMS [I]、NUMS [L]、NUMS [R])))。 16 一方(L <R && NUMS [L] == NUMS [L + 1])L ++。// 場合に左側の要素は繰り返しである 17 ながら(L <R && NUMS [R] == NUMS [R-1])r--の。 18 L ++; r--の。 19 } 20 他の 場合(合計<0){ //は、左側要素が大きいことを意味 21 ++ L 。 22 } 23 他の 場合(和> 0){ //は正しい要素が大きい手段 24 r--の。 25 } 26 } 27 ながら(I + 1 <nums.length && NUMS [I + 1] == NUMS [I]){ //場合に、それが反復され、 28 iは++ ; 29 } 30 I ++ 。//繰り返し実行させる 31 Lは、I + 1 =を。 32 R = nums.length-1 。 33 } 34 リターンsumlist。 35 }
二考慮しなかった最初のIで私を++サイクルアップを実行できます。
後決意条件でサイクルに添加されていないI + 1 <nums.length、配列の境界を行います。
以下のためにL心配がないわけではありません。後最初の層の循環に直接見出され、加えIのようなサイクル決意条件。
要約:
この質問は私に悪いトスを与えました。
- これらの内容は難しくありませんが、実装プロセスの間の相関は、コードは非常にストレスです。したがって、実施の注文後、すなわち、特定のロジックを区別する。
- 最初のトラブルが発生しましたさらに算術問題、ライン15内の2つの完全なコード溶液、コードの16行で始まるでL <Rの裏面に条件、だから常に配列の境界、Iでした、エラーのプログラムの実行をかなり理解し、そして私は、操作の交差点を数え、左から右にあるので、配列境界の姿はなかったです。
- 最後に、ライン27は、コードの行30、私は総クロスボーダーは、時間の素晴らしい半分をいじくり回しますか?その後、穏やかで、それについて考え、このようなものは非常に単純なShayaは、持っています。私は、各ステップの重要性をクリアしなかったこと。例えば、いくつかのコードの30行を削除しているが、これは唯一の実行可能性が存在し、上記サイクルを防止することです。ループ部は、一部の人々は$ NUMSを使用し、絶えず決意条件といじくりある[I] == NUMS [I-1] $、この目的を達成するために、私が使用したdo-ながら声明、トスは、境界条件につながる非常にあります混乱。実は、私はいくつかの文が似ていると思いますが、より多くのロジックの実行が異なるので、そのラインとコードは、自分の時間や状況になり、その境界条件を定義する必要がありますよりも、何もありません。