leetcode 15.三数之和(双指针,realloc问题,缓存区溢出问题)

leetcode 15.三数之和(C语言)

题目链接:leetcode 15.三数之和
题目描述:
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。

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

给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

题解: 第一眼看这题一般首先会觉得很简单,不就是直接枚举嘛,后来看到不包含重复觉得问题并不是很简单,有仔细想想超时的问题,方法又 变得有待优化,再仔细一看题目还没有限制数据长度范围。仔细推敲后发现这还是一道不是那么简单的题目。但是等我们用起C语言开始写代码时,更是会遇到种种问题,因为C语言并不想其他语言那么方便简洁,所以也很考验我们C语言学的怎么样。
思路: 在讲解思路之前,我们可以先回忆另外一道题leetcode 1.两数之和,看完这道题,再联想这道题,估计就有了思路。题目中让我们找到a+b+c=0,我们可以把a当做求解两数之和的target。 然后我认为还是在穷举的前提下做优化,优化方法还是两种,即双指针和二分优化。

还是先上代码;

int cmp(const void*a,const void*b)   //qsort的比较函数
{
    return *(int*)a-*(int*)b;
}
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
    *returnSize=0;
    if(numsSize<3)        //*returnSize=0;一定要注意放在这之前
    return NULL;
    qsort(nums,numsSize,sizeof(nums[0]),cmp);   //stdio.h中的快速排序函数
    int i=0,left=0,right=0,target=0,sum=0;
    int** ans = (int**)malloc(sizeof(int*)*(numsSize)*(numsSize ));   //为返回结果的数组分配空间,至于为什么是numsSize*numsSize,后面会说明
    *returnColumnSizes = (int*)malloc(sizeof(int)*(numsSize)*(numsSize));     //这个是存放每一行的列数的数组,实际上不用算,就是3
    for(i=0;i<numsSize-2;i++){
        if(nums[i]>0)     
        break;     //因为是从大到小序列,a,b,c>0,等式恒不成立
        while(i>0&&i<numsSize-2&&nums[i]==nums[i-1])
        i++;       //选取target去重
        target=-nums[i];
        left=i+1;
        right=numsSize-1;
        while(left<right){    //双指针
            sum=nums[left]+nums[right];
            if(sum<target){
                left++;       //while(left<right&&nums[left]==nums[++left]);可以在这里也去重,但没必要
                continue;
            }
            if(sum>target){
                right--;
                continue;
            }
            ans[*returnSize]=(int*)malloc(sizeof(int)*3);
            ans[*returnSize][0]=-target;
            ans[*returnSize][1]=nums[left];
            ans[*returnSize][2]=nums[right];
            (*returnColumnSizes)[*returnSize]=3;
            *returnSize=*returnSize+1;
            while(left<right&&nums[left]==nums[++left]);
            while(right>left&&nums[right]==nums[--right]);//去重
        }
    }
    return ans;
}


注释中就有一些小细节,还有就是关于数组大小问题。
我认为是可以推算出(numsSize*numsSize)的空间是完全足够的。
要使得a+b+c=0;(假定a<b<c)
那么就必定有:a<0&&c>0恒成立
然后假设将nums排序后有x个负数,n-x个正数
a有x种可能的值,c有(n-x)种可能的取值,假设无论a和c在任意允许的取值情况都有对应的b存在(这种假定虽然不存在),那么空间就是n*(n-x),所以我认为分配(numsSize*numsSize)的数组大小是完全够的。
可能还可以把范围再降低一个级别,如果你知道,请一定私信或者在评论区告知你的方法。

**可能还有人会尝试用C语言里面的realloc函数,**我也尝试了很久,但是都失败了,realloc本身是一个容易造成问题的函数。
我用的realloc分配数组空间提交后,显示超出时间限制,有两个测试用例没过就超时了,如果你们有用realloc函数通过测试的,希望你能私信,或者在评论区留言。

/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */
int cmp(const void*a,const void*b)
{
    return *(int*)a-*(int*)b;
}
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
    *returnSize=0;
    if(numsSize<3)
    return NULL;
    qsort(nums,numsSize,sizeof(nums[0]),cmp);
    int i=0,left=0,right=0,target=0,sum=0;
    int **ans=(int**)malloc(sizeof(int*));
    *returnColumnSizes = (int*)malloc(sizeof(int) * (numsSize - 2) * (numsSize - 2));
    for(i=0;i<numsSize-2;i++){
        if(nums[i]>0)
        break;
        while(i>0&&i<numsSize-2&&nums[i]==nums[i-1])
        i++;
        target=-nums[i];
        left=i+1;
        right=numsSize-1;
        while(left<right){
            sum=nums[left]+nums[right];
            if(sum<target){
                while(left<right&&nums[left]==nums[left+1])
                left++;
                left++;
                continue;
            }
            if(sum>target){
                while(right>left&&nums[right]==nums[right-1])
                right--;
                right--;
                continue;
            }
            ans=(int**)realloc(ans,sizeof(int*)*(*returnSize+1));
            ans[*returnSize]=(int*)malloc(sizeof(int)*3);
            ans[*returnSize][0]=-target;
            ans[*returnSize][1]=nums[left];
            ans[*returnSize][2]=nums[right];
            (*returnColumnSizes)[*returnSize]=3;
            *returnSize=*returnSize+1;
            while(left<right&&nums[left]==nums[++left]);
            while(right>left&&nums[right]==nums[--right]);
        }
    }
    return ans;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值