T15の3つのLeetCodeブラッシング質問の合計(中)

今回説明するトピックは、LeeCodeの中程度のトピックである3つの数値の合計です。言うまでもなく、トピック:

ここに画像の説明を挿入
多くの人が最初に考えたのは、暴力的な解決策、3層のループ、私もそうだと思いますが、それは大きな間違いです!この質問には非常に重要なポイントがあるので、それは重複を取り除くことです!
問題解決のアイデア:
1:最初に配列を並べ替えます!これの利点は、次に重複を削除するときに、より直感的で便利になることです!
2:3つのポインター、最初のポインターは配列をトラバースし、index = 0の位置からindex = nums.length-3の位置まで、つまり最初から最後から3番目の位置までトラバースします
。3:他の2つのポインターこれはヘッドポインタ、テールポインタであり、ヘッドはi + 1から始まり、テールは配列の最後からトラバースします。
4:最も重要な場所はここにあります。頭と尾のトラバーサルのルール:
(1)sum <0(3つのポインターが指す数値の合計)の場合、頭は右に移動する必要があります。これは、この方法でのみ、より大きくなることが保証されるためです。同様に、sum> 0の場合、合計が小さくなるため、テールを左に移動する必要があります。
(2)nums [i]> 0の場合、i + head + tailは0より大きくなければならないため、直接終了できます。
(3)重複排除、ソートされているため、sum = 0の条件を満たすことができれば、バック++に進む必要があります。また、2つが必ずしも接続されているとは限らないため、ここで判断する必要があります。 、または2を超える場合は、一度に接続されている複数の番号を除外できます。
図に示すように:
ここに画像の説明を挿入
次に、コード:

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        //定义返回的集合
        List<List<Integer>> lists=new ArrayList();
        Arrays.sort(nums);
        //遍历 从头一直遍历到倒数第三个
        for(int i=0;i<nums.length-2;i++){
            if(nums[i]>0) break; //如果此时已经大于0就说明后面全为整数再加也不会等于0
             int head=i+1;//定义头指针
             int tail=nums.length-1;//定义尾指针
             if(i>0&&nums[i]==nums[i-1]) continue; //如果连续相等的话就说明重复了,跳到下一个
             //当头指针和为指针相遇的时候结束循环
              while(head<tail){
                  int sum=nums[i]+nums[head]+nums[tail];
                  //满足条件时
                if(sum==0){
                    lists.add(Arrays.asList(nums[i],nums[head],nums[tail]));
                    while(head<tail&&nums[head]==nums[head+1]) head++; //头指针去重  这里要用while 不能用if 因为如果三个或者更多个相同的数字连在一起还是会重复,因为排了序,索性就让head或者tail继续移动到不后面不重复的地方 另外一个条件的作用就是防止head或者tail相遇 细节:这里head<tail需要先判断 [0,0,0] 这种情况,head会越界如果先,判断进行nums[head]==nums[head+1]的话就会数组下标越界
                    while(head<tail&&nums[tail]==nums[tail-1]) tail--; //尾指针去重
                    head++;
                    tail--;
                }
                //说明此时head指针需要往后移动,因为这样才能使sum变大
                else if(sum<0) {head++;}
                //说明此时tail指针需要往后移动,因为这样才能使sum变小
                else if(sum>0) {tail--;}
              }
        }
        return lists;
    }
}

詳細な説明:
1:if(nums [i]> 0)break;この時点ですでに0より大きい場合は、以下のすべてが整数であり、0に等しくないことを意味します。これはすでに
2 と言われていますwhile(head <tail && nums [head] == nums [head + 1])head ++;なぜここで使用するのですか?ifを使用すると、判断は1回だけになります。つまり、sum = 0の場合、頭と頭の後の要素は同じで重複がなくなりますが、頭の後に彼と等しい要素が3つ以上あるかどうかは考慮されません。それは機能しないので、ここではwhile
3 を使用する必要があります(簡潔にするためにテールを重ねません!)while(head <tail && nums [head] == nums [head + 1])head ++;この場所を説明する必要があります!作者がここで捕まったから!
while(nums [head] == nums [head + 1] && head <tail)head ++;この方法と上記の方法に違いはありますか?一見同じように見えますが、場所が違うことがわかります!しかし、どのような影響がありますか?ねえ、私はここで間違えました!次に、私の分析を聞いてください:
[0,0,0]この場合、3つは等しいです。判断では、ヘッドは++の操作を実行し、テールは-の操作を実行しますが、長さが3であるため、操作が完了すると、ヘッドとテールの位置が交換されます。ヘッドがwhileループで++を通過すると、ヘッド+1が境界を越えます。while(nums [head] == nums [head]を使用すると、 +1] && head <tail)このようにして、headとhead + 1の位置が等しいかどうかが判断され、配列の添え字が範囲外の例外になります。したがって、頭<尾を最初に判断する必要があります!
ここに画像の説明を挿入

これがこのトピックの説明です。それがすべての人に役立つ場合は、それに注意してください。質問がある場合は、メッセージを残してください。皆さん、ありがとうございました!

おすすめ

転載: blog.csdn.net/Pzzzz_wwy/article/details/105719833