LeetCode 15 三数之和(数组、双指针)

16 篇文章 0 订阅

题目要求:

给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

 

 

C++代码1:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> result;
        sort(nums.begin(),nums.end());
        for(int i=0;i<nums.size();++i){
            if(i>0 && nums[i-1]==nums[i]){
                continue; //skip duplicate
            }
            int j=i+1,k=nums.size()-1;
            while(j<k){
               int sum=nums[i]+nums[j]+nums[k];
               if(sum<0){
                   ++j;
               }
               else if(sum>0){
                   --k;
               }
               else{
                    vector<int> temp_result(3,nums[i]);
                    temp_result[1]=nums[j];
                    temp_result[2]=nums[k];
                    if(!count(result.begin(),result.end(),temp_result)){
                       result.push_back(temp_result);
                    }
                    j++;
                    k--;
                }
            }
        }
        return result;
    }
};

 

 

 

 

结果(超出时间限制):

 

 

 

解析:

首先对nums数组里的数字先排序

sort(nums.begin(),nums.end());

对输入的数字进行遍历获得第一个数

for(int i=0;i<nums.size();++i)

然后在计算后面两数的和的时候可以设两个迭代器

一个从该数的后一个数开始(j=i+1),一另个从最后一个数开始(k=nums.size()-1)

如果加和小了就移动第一个迭代器

if(sum<0){
   ++j;
 }

如果加和大了就移动第二个迭代器

else if(sum>0){
   --k;
}

就可以遍历所有情况了,遇到sum=0的就保存起来

不过最终超出时间限制!!!

需要改进!

 

 

 

C++代码2:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> result;
        if(nums.size()<=2)return result;
        sort(nums.begin(), nums.end());
        for (int i = 0; i < nums.size() - 2; i++) {
            int a = nums[i];
            if(a > 0) break;
            if (i > 0 && a == nums[i - 1]) continue;
            for (long j = i + 1, k = nums.size() - 1; j < k;) {
                int b = nums[j];
                int c = nums[k];
                int value = a + b + c;
                if (value == 0) {
                    result.push_back(vector<int>({a, b, c}));
                    while (j<k && b == nums[++j]);
                    while (j < k &&c == nums[--k]);
                } else if (value > 0) {
                    k--;
                } else {
                    j++;
                }
            }
        }
        return result;
    }
};

 

 

 

 

结果:

 

 

 

 

 

解析:

其实大致思路还是跟代码1差不多,只不过数字整个都是排序的,如果有重复数字肯定是相邻的,我们在处理完前一个数之后,如果后一个数与之相等就删掉,这样避免了重复情况的出现

即多了

if (i > 0 && a == nums[i - 1]) continue;

以及

while (j<k && b == nums[++j]);
while (j < k &&c == nums[--k]);

 

详细解释如下:

首先定义一个双层的int类型的vector容器装结果result

vector<vector<int>> result;

然后判断,因为我们是求三数之和,如果nums里的元素小于等于2的话,就直接返回result,因为当前的result为空

if(nums.size()<=2)return result;

然后就是先对元素排序,目的就是我们在固定好第一个元素后,第二个元素取该数的后一个数,第三个元素从最后一个数开始,它们的和如果大于(0-第一个元素)的结果,那么第三个元素就减小,如果小于(0-第一个元素)的结果,那么第二个元素就增大

sort(nums.begin(), nums.end());

然后对于从第一个元素开始,逐渐遍历每一个元素,注意,因为需要判断三数之和,所以最后一个需要判断的数字是nums.size() - 2

for (int i = 0; i < nums.size() - 2; i++)

把第一个元素的值赋给变量a

int a = nums[i];

因为已经排好序了,所以从左边开始,第一个数肯定是当前nums里最小的了,如果它的值都大于0了,那么nums里就不可能存在三数之和刚好等于0,所以直接break退出循环

if(a > 0) break;

然后就是做一个判断,如果有重复数字肯定是相邻的,我们在处理完前一个数之后,如果后一个数与之相等就删掉,这样避免了重复情况的出现

if (i > 0 && a == nums[i - 1]) continue;

然后再进行一个for循环,j也就是第二个元素的初始值,去第一个元素的下一位元素,而k是第三个元素的初始值,取最后一个元素

for (long j = i + 1, k = nums.size() - 1; j < k;)

把它们的值分别赋给b和c

int b = nums[j];
int c = nums[k];

然后求当前三数之和value

int value = a + b + c;

如果刚好三数之和value等于0了,那么就把a,b,c做成一个vector,然后push_back进result里

然后只要j的值和它右边的值相同,或者k的值和它左边的值相同,那就是重复的可能性了,这时,直接不进行任何操作

if (value == 0) {
    result.push_back(vector<int>({a, b, c}));
    while (j<k && b == nums[++j]);
    while (j < k &&c == nums[--k]);
 }

如果三数之和value大于0,那么我们就把第三个元素k减小,也就是向左移动一位,k--

else if (value > 0) {
    k--;
 }

如果三数之和value小于0了,那么我们就把第二个元素j增大,也就是向右移动一位,j++

else {
    j++;
 }

最后 return result; 即可

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值