码迷,mamicode.com
首页 > 其他好文 > 详细

Leetcode-15. 三数之和

时间:2019-12-10 22:21:03      阅读:88      评论:0      收藏:0      [点我收藏+]

标签:剪枝   整数   eof   sort   操作   集合   amp   log   位置   

题目

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

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

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

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

思路

要求的是a+b+c=0 其实就是要求a+b=-c,那么问题可以转化为依次遍历数组元素c,然后在剩下的数中做两数之和为-c的问题。

 

问题在于如何简化算法以及优化复杂度。 1.首先可以先排序(O(nlogn)),这样保证数组有序之后可以利用大小关系判断。

 

2.设置两个指针left、right,分别从左边以及右边向中间遍历,如果找到a+b+c==0,那么可以将这个答案加入到答案集里 如果a+b+c<0,此时固定的是c,说明a+b太小了,因此left+=1;如果a+b+c>0,此时a+b过大,因此right-=1

 

3.去重,这一步则是利用了有序性,如果两个数相同,那他们在数组的位置一定是相邻的(连着几个数相同也是可能的),因此 去重的操作就能简单遍历一下相邻的是否相同即可。由于数组有序性使得去重这一步很简单,因此也可以看出第一步的作用。

 

此外还有一些小细节的地方,比如说当遍历到c>0的时候,由于之后的数都是正数,那三数之和一定大于0,就没必要继续遍历c了(因为 继续向后遍历c只会更大,那之后的数加起来一定大于0); 或者固定c,如果c及其后面连着两个数a,b,他们的和已经大于0了,就没必要进行下一步的操作,此时遍历下一个c; 同理,如果c和数组最后两个数的和仍然小于0,也没必要进行下一步操作。
 

代码

//最大答案数
#define MAX_ANS_NUM 1000000

int comp(const void* a, const void* b) {
    return *((int*)a) - *((int*)b);
}

int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
    int** result = (int**)calloc(MAX_ANS_NUM, sizeof(int*));
    *returnColumnSizes = (int*)calloc(MAX_ANS_NUM, sizeof(int));
    *returnSize = 0;
    if (numsSize < 3) return result;
    //先将入参排序
    qsort(nums, numsSize, sizeof(int), comp);
    //排除极端异常情况:
    if (nums[0] + nums[1] + nums[2] > 0) return result; // 最小三个数相加都大于0直接无解
    if (nums[numsSize - 1] + nums[numsSize - 2] + nums[numsSize - 3] < 0) return result; //最大三个数相加都小于0直接无解

    int left, right, anscount;
    anscount = 0;
    for (int i = 0; i < numsSize - 2; i++) 
    {
        if (nums[i] + nums[i + 1] + nums[i + 2])
        {
            if (nums[i] + nums[numsSize - 1] + nums[numsSize -2] < 0) 
            continue; // 剪枝优化无效判断 最小的加上 最大的两个数都小于0继续找下一轮
        }
      
        if (i > 0 && nums[i] == nums[i - 1]) 
        {
            continue; // 重复的判断
        }

        left = i + 1;
        right = numsSize - 1;

        while (left < right) 
        {
            if (nums[left] + nums[i] + nums[right] == 0) 
            {
                result[anscount] = (int*)calloc(3, sizeof(int));
                result[anscount][0] = nums[left];
                result[anscount][1] = nums[i];
                result[anscount][2] = nums[right];
                (*returnColumnSizes)[anscount] = 3;
                anscount++;
                while(left + 1 < right && nums[left] == nums[left + 1]) 
                {
                    left++;
                }
                left++;
                while (left < right - 1 && nums[right] == nums[right - 1]) 
                {
                    right--;
                }
                right--;
            } else if (nums[left] + nums[i] + nums[right] < 0) 
            {
                left++;
            } else if (nums[left] + nums[i] + nums[right] > 0) 
            {
                right--;
            }
        }
    }

    *returnSize = anscount;
    return result;
}

 

 

Leetcode-15. 三数之和

标签:剪枝   整数   eof   sort   操作   集合   amp   log   位置   

原文地址:https://www.cnblogs.com/mhq-martin/p/12019500.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!