LeetCode刷题之T15三数之和(中等)

这次我们讲解的题目是LeeCode 的中等题目,三数之和。话不多说,上题目:

在这里插入图片描述
相信很多人的第一个想法就是,暴力求解,三层for循环,我也是,可是却是一个大大的错误!因为这道题有个很重要的点,那就是去重!
解题思路:
1:先将数组进行排序! 这样的好处是再接下来去重的时候能更加直观方便!
2:三个指针,第一个指针对数组进行遍历,从index=0的位置一直遍历到index=nums.length-3的位置,也就是从头到倒数第三个的位置
3:另外两个一个是head指针,一个tail指针,head为i+1开始,tail从数组尾开始遍历。
4:最重要的地方来了,head和tail遍历的规则:
(1)如果如果sum<0(三个指针所指的数的和),则说明head需要向右边移动,因为只有这样才能保证大于sum变大,同理的,如果sum>0,那么tail需要往左边移动,因为这样才能sum变小
(2)如果nums[i]>0 则可直接退出,因为i+head+tail必定大于0
(3)去重,因为已经排序过了,那么如果的i能满足sum=0的情况,我们就需要继续往后面++,同时这里需要while来判断,因为不一定是两个是连在一起,也可能是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++; 这里为什么用while呢??因为如果用if的话只进行了一次判断,也就是说如果当sum=0时,head和head后面那一个元素相同去重了,但是并没有考虑到如果head后面有两个以上和他相等呢??那就不行了,所以此处要用while
3:(为了简洁就不把tail摆过来了!)while(head<tail&&nums[head]==nums[head+1]) head++; 这个地方需要重点说明!!!!!!!!!因为笔者在这里中坑了!!!
while(nums[head]==nums[head+1]&&head<tail) head++; 这种方式和上面的方式有什么不同吗??乍一看好像一样,你会发现位置不同!但是有什么影响呢??哎我就是在这里犯错了!接下来听我分析:
[0,0,0]这种情况,三个固然是相等的,进入判断,head会进行++的操作同时tail会进行--的操作,但是因为长度为3,这样一操作完,head和tail的位置就进行了互换,head在while循环这里经过++后,这样就导致我们的head+1越界了,如果我们使用while(nums[head]==nums[head+1]&&head<tail) 这种方式的话就会先对head和head+1的位置进行判断是否相等的操作,这就会导致数组下标越界异常!!所以我们得先进行head<tail的判断!!!
在这里插入图片描述

这就是本次题目的讲解,如果能够帮助到大家,欢迎点个关注,如果有疑问,欢迎留言!谢谢大家!

猜你喜欢

转载自blog.csdn.net/Pzzzz_wwy/article/details/105719833
今日推荐