力扣题15:三树之和(c++)

题目:给你一个整数数组nums,判断是否存在一元组 [nums [i],nums[j],nums[k]] 满足 i != ji != k j != k ,同时还满足 nums [i] +nums[j] + nums[k] == 0 。请你返回所有和为  且不重复的三元组
注意: 答案中不可以包含重复的三元组

 解:(1)分析:

由题目可知,我们要在给的整数数组中找出和为0的三元组,要注意的是找到的三元组中不能出现重复下标

优化1:

如果我们使用三重循环枚举出所有的三元组,然后使用哈希表去重操作,得到不包含重复三元组的最终答案,这个做法的时间复杂度和空间复杂度都很高,所以我们要将三重循环优化和修改。

为了使三数组不重复,我们保持三重循环的大框架不变的情况,将数组进行排序,保证:

  • 第二重循环枚举到的元素不小于当前第一重循环枚举到的元素;
  • 第三重循环枚举到的元素不小于当前第二重循环枚举到的元素

我们枚举的三元组 (a, b, c)满足 a≤b≤c,保证了只有 (a,b,c) 这个顺序会被枚举到,而(b, a, c)、(c, b, a) 等等这些不会出现,这样就减少了重复。

优化2:

同时,对于每一重循环而言,相邻两次枚举的元素不能相同,否则也会造成重复。举个例子,如果排完序的数组为

[0, 1, 2, 2, 2, 2, -1]

我们枚举到的第一个三元组为(012),如果第三重循环继续枚举下一个元素,那么仍然是三元组 (0,1,2),产生了重复。因此我们需要将第三重循环「跳到」下一个不相同的元素,即数组中的最后一个元素 -1,枚举三元组 (0, 1, -1)。我们可以在循环中添加if语句判断。

优化3:

虽然已经简化一些,但我们仍旧还是三重循环的框架,为了进一步减少我们引入双指针,我们固定二重枚举的元素ab,此时唯一的 c 满足 a+b+c = 0。如果此时的第三层循环的元素不满足,那么当新的第二重循环在b后枚举一个元素b时,由于b’> b那么满足a+b+c'=0c’一定有 c< c,也就是说c’一定出现在 c 的左侧所以,我们可以认为从小到大枚举b的同时从大到小枚举 c,即第二重循环和第三重循环实际上是并列的关系.而代码的时间复杂度也从ON3)变为ON2)。

(2)代码:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int n=nums.size();
        vector<vector<int>>vec;
        sort(nums.begin(),nums.end());
        for(int first=0;first<n;first++){//枚举a
            if(first>0 && nums[first]==nums[first-1]){//保证和上一次枚举的数不相同,减少重复
                continue;
            }
            int third=n-1; //使c指针指向数组最右端
            int target=-nums[first];
            for(int second=first+1;second<n;second++){//枚举b
                if(second>first+1&&nums[second]==nums[second-1]){//保证和上一次枚举的数不相同,减少重复
                    continue;
                }
                while(third>second&&nums[second]+nums[third]>target){//保证 b 的指针在 c 的指针的左侧
                    --third;
                }
                if(third==second){//如果指针重合,随着 b 后续的增加就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
                    break;
                }
                if(nums[second]+nums[third]==target){
                    vec.push_back({nums[first],nums[second],nums[third]});}
                }
            
            }
        
        
        return vec;
        }
    
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值