【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]
]

二、题解

思路为:

  1. 当输入size < 3 时,直接返回空

  2. 当输入size >=3时,分配内存 n * ( n-1 ) / 6
    假设所有的数相加都等于0n 个数,每三个数一组,共有 n-2 + n-3 + n-4 + ....+ 1 种情况,共 n * ( n-1 ) / 2 种,但在这种情况下是不可能的。因为题目要求不可重复。
    所以,取的值 比 (size-1)*(size-2)/2 小就可以。
    考虑到,当 输出size 为 3 时, n * ( n-1 ) = 6, 所以被除数最大为 6
    所以此处,分配内存大小为 n * ( n-1 ) / 6

  3. 设立三个指针,current, left, right
    current 取值范围为[0, size-2]
    left 及 right 的取值范围为 [ current, size-2]left++, right-- , 当 left >= right 时该轮遍历结束

  4. 排除一些错误解,由于 current 是最小的,right 是最大的
    current >=0 时,最终结果肯定 > 0
    right <=0 时,最终结果肯定 < 0

三个指针移动过程如下图:
在这里插入图片描述

// 排序,从小到大排序, 双向排序
void sort_array(int *nums, int numsSize)
{
    // 定义左右指针
    int *left = nums;                   // 左
    int *p;
    int *right = nums + numsSize - 1;   // 右
    int tmp, *p_tmp;
    // 排序前打印数组
    printf("排序前:");
    for(tmp = 0; tmp < numsSize; tmp++)
        printf(" %3d ", nums[tmp]);
    printf("\n");

    while(left <= right){
        p = left;
        while( p <= right )
        {
            if(*left > *p || *p > *right){
                p_tmp = *left > *p ? left : right;
                tmp = *p;
                *p = *p_tmp;
                *p_tmp = tmp;
            }
            p++;
        }
        left++;		right--;
    }
    printf("排序后:");
    for(tmp = 0; tmp < numsSize; tmp++)
        printf(" %3d ", nums[tmp]);
    printf("\n");
}

/**
 * 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** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){

    int *left, *current, *right, **returen_array;
    int i = 0;

    *returnSize = 0;
    // 当空组内容不合规时,直接返回空
    if(numsSize < 3){
        return NULL;
    }
    
    // 分配内存
    returen_array = (int **)malloc(sizeof(int *) * (numsSize - 1) * (numsSize ) / 6  );	// 记录数组大小,array[i][j]中的 i
    *returnColumnSizes = (int *)malloc( sizeof(int) * (numsSize - 1) * (numsSize ) / 6 );// 记录每个元素的大小,array[i][j]中的 j

    // 对数组进行排序
    sort_array(nums, numsSize);

    // 思路就是 current,指向开头,
    current = nums;
    while(current < nums + numsSize -2 && *current <= 0){  // 如果 *current 大于0 时,不用计算了,总值肯定 >0

        left = current+1;
        right = nums + numsSize -1;

        while(left < right && *right >= 0){  // 如果 *right 小于0时,不用计算了,总值肯定 <0 

            // 当输入数据很多时,开启log 会报错 超出输出限制,此时注释log即可
            //printf("第 %d 轮 current=%d, left=%d , right=%d, -- *returensize=%d \n", 
            			//current - nums,   *current, *left,  *right, *returnSize);
            if( *left + *current + *right == 0)
            {
                // 每找到一组,就动态分配内存
                 *(returen_array + *returnSize) = (int *)malloc(sizeof(int) * 3);     
                returen_array[*returnSize][0] = *left;
                returen_array[*returnSize][1] = *current;
                returen_array[*returnSize][2] = *right;
                (*returnColumnSizes)[*returnSize] = 3;
                (*returnSize)++;

                while( *left == *(++left) && left < right );	// 去重
                while( *right == *(--right) && left < right );	// 去重

            }else if( *left + *current + *right < 0 ){
                left++;
            }else{
                right--;
            }
        }
        while(*(++current) == *(current-1) && current < nums + numsSize -1 );       // current 去重
    }
    return returen_array;
}

运行结果如下:
在这里插入图片描述

排序前:  -1    0    1    2   -1   -4 
排序后:  -4   -1   -1    0    1    20 轮 current=-4, left=-1 , right=2, -- *returensize=00 轮 current=-4, left=-1 , right=2, -- *returensize=00 轮 current=-4, left=0 ,  right=2, -- *returensize=00 轮 current=-4, left=1 ,  right=2, -- *returensize=01 轮 current=-1, left=-1 , right=2, -- *returensize=01 轮 current=-1, left=0 ,  right=1, -- *returensize=13 轮 current=0,  left=1 ,  right=2, -- *returensize=2 

输出:  [[-1,-1,2],[0,-1,1]]

三、leetcode 中 超出输出限制 错误解析

在这里插入图片描述

原因为打印的log 太多,此时注释相关重复的printf log 即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

"小夜猫&小懒虫&小财迷"的男人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值