今回説明するトピックは、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の位置が等しいかどうかが判断され、配列の添え字が範囲外の例外になります。!!したがって、頭<尾を最初に判断する必要があります!!!
これがこのトピックの説明です。それがすべての人に役立つ場合は、それに注意してください。質問がある場合は、メッセージを残してください。皆さん、ありがとうございました!