leetcode算法题15---求三数之和

算法学习复盘

  算法小白最近复习完c语言和c++后在尝试着做算法题,遇到了一道于自己而言是难题的题目。打算在这里复盘一下。
  整体思路:求三个数之和,通过枚举算法也可解,但是时间效率太低,所以应当先对数组进行排序,然后通过双指针不断向内搜索,减少比较次数。具体实现可看第三版

第一版

这是第一次写的代码,并未通过

/**
 * 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;
    }
    //利用c库函数的快排
    qsort(nums, numsSize, sizeof(int), cmp);
    int **ret = (int **)calloc(numsSize, sizeof(int *));
    *returnColumnSizes = (int *)calloc(numsSize, sizeof(int));

    int i = 0;
    while ((i < numsSize) && (nums[i] < 0))
    {
        int j = i + 1, k = numsSize - 1;
        while (j < k)
        {
            if ((nums[i] + nums[j] + nums[k] > 0))
            {
                k--;
                //printf("%d,%d,%d\n", nums[i], nums[j], nums[k]);
            }
            else if (nums[i] + nums[j] + nums[k] < 0)
            {
                j++;
                //printf("%d,%d,%d\n", nums[i], nums[j], nums[k]);
            }
            else
            {
                ret[*returnSize] = (int *)calloc(3, sizeof(int));
                ret[*returnSize][0] = nums[i];
                ret[*returnSize][1] = nums[j];
                ret[*returnSize][2] = nums[k];
                (*returnColumnSizes)[*returnSize] = 3;
                (*returnSize)++;
                while (nums[j] == nums[++j])
                    ;
                while (nums[k] == nums[++k])
                    ;

                //记录值
                //printf("%d,%d,%d\n", nums[i], nums[j], nums[k]);
            }
        }
        i++;
    }
    return ret;
}

存在的问题:
1.未在意英文注释说明的内容,连题目要求做什么都没弄清楚
2.第一个while循环中有两个问题:
  首先是i应当小于numsSize-2,否则在后面j和k的数组访问会越界。
  然后是nums[i]应当小于等于0,否则会忽略了[0,0,0,0]的情况
3.while (nums[k] == nums[++k])
由于外层的while循环判断需要内部代码块执行完才结束,所以会出现不断循环导致越界
4.申请的内存空间不足,容易溢出
5.i自增的前提条件不对

第二版

第二版,部分通过,有些问题超时了

/**
 * 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;
    }
    //利用c库函数的快排
    qsort(nums, numsSize, sizeof(int), cmp);

    int **ret = (int **)malloc(numsSize * numsSize * sizeof(int *));
    *returnColumnSizes = (int *)malloc(numsSize * numsSize * sizeof(int));

    int i = 0;
    while ((i < numsSize) && (nums[i] < 0))
    {
        while (i > 0 && nums[i] == nums[i - 1])
        {
            i++;
        }
        int j = i + 1, k = numsSize - 1;
        while (j < k)
        {
            if ((nums[i] + nums[j] + nums[k] > 0))
            {
                k--;
            }
            else if (nums[i] + nums[j] + nums[k] < 0)
            {
                j++;
            }
            else
            {
                ret[*returnSize] = (int *)malloc(3 * sizeof(int));
                ret[*returnSize][0] = nums[i];
                ret[*returnSize][1] = nums[j];
                ret[*returnSize][2] = nums[k];
                (*returnColumnSizes)[*returnSize] = 3;
                (*returnSize)++;
                while (nums[j] == nums[++j])
                    ;
                while (nums[k] == nums[--k])
                    ;
            }
        }
        i++;
    }
    return ret;
}

存在问题:
1.第一个while循环中有两个问题:
  首先是i应当小于numsSize-2,否则在后面j和k的数组访问会越界。
2…while (nums[k] == nums[++k])
  由于外层的while循环判断需要内部代码块执行完才结束,所以会出现不断循环导致越界
  然后是nums[i]应当小于等于0,否则会忽略了[0,0,0,0]的情况
3.申请的内存空间不足,容易溢出
  貌似除了昨天晚上用了一晚时间学会了审题hhhh

第三版

  目前的最新版本
  通过一个晚上学习leetcode上大神的解法,终于把自己的思路捋清楚了,才拿到ac

/**
 * 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)
{
    //对数组排序
    qsort(nums, numsSize, sizeof(int), cmp);
    int i = 0, j = 0, k = 0, sum = 0;
    *returnSize = 0;
    //最大空间的确定
    //极限情况下,第i轮有(numsSize-i)/2个(i>0)
    //共有numsSize-2轮
    //所以求和得
    //(numsSize-1)/2+(numsSize-2)/2....+(numsSize-numsSize+2)/2
    //1/4*(2+numsSize-1)*(numsSize-2)
    //1/4*(numsSize+1)*(numsSize-2)
    //确定上界,比它大都行
    //由于不需要太精确,所以可以把1/4乘进括号内得
    //(numsSize+1/4)*(numsSize-1/2)
    //由于c语言的下取整,可直接取numsSize*numsSize
    //我试过测试集内不存在这么极限的情况,即便是(numsSize-2)*(numsSize-2)也能ac
    int **ret = (int **)calloc(numsSize * numsSize, sizeof(int *));          //为返回数组申请空间
    *returnColumnSizes = (int **)calloc(numsSize * numsSize, sizeof(int *)); //为返回数组大小申请空间
    while ((i < numsSize - 2) && (nums[i] <= 0))
    {
        if (numsSize < 3)
        { //数组不足3个元素
            return NULL;
        }
        j = i + 1, k = numsSize - 1;
        while (j < k)
        {
            sum = nums[i] + nums[j] + nums[k];
            if (sum == 0)
            {
                //printf("记录:%d %d %d\n", nums[i], nums[j], nums[k]);
                ret[*returnSize] = (int *)calloc(3, sizeof(int));
                ret[*returnSize][0] = nums[i];
                ret[*returnSize][1] = nums[j];
                ret[*returnSize][2] = nums[k];
                (*returnColumnSizes)[*returnSize] = 3;
                (*returnSize)++;
                //去重
                while ((j < k) && (nums[j] == nums[++j]))
                    ;
                while ((j < k) && (nums[k] == nums[--k]))
                    ;

                //去除重复的ii
                //i应该小于numsSize-2,防止后面越界
            }
            else if (sum < 0)
            {
                j++;
            }
            else
            {
                k--;
            }
        }
        while ((i < numsSize - 2) && nums[i] == nums[++i])
            ;
        //printf("%d %d %d\n", nums[i], nums[j], nums[k]);
        //保证循环
    }
    return ret;
}

目前发现的问题:
1.申请的空间过大,存在浪费

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值