列举三数之和

题目

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。

示例:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。

输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。

思路

解法1:设置三层循环一次列举,时间复杂度为n^3。
解法2:首先对原始数组按从小到大排序,然后对每一个元素遍历,每次遍历再设立高低指针,设立二层循环遍历,如果和小于0,则高指针减一,和大于0则低指针加一。知道找到一组等于0的数,高低指针都减一和加一找下一组。其中为了保证不重复,找低指针时找第一个不重复的最小值,找高指针时找第一个不重复的最大值。

参数:
int* nums, 原始数组
int numsSize,原始数组大小
int* returnSize, 返回二维数组第一维大小
int** returnColumnSizes返回二维数组第二维大小(这里都是3,因为是三个数的和)

/**
 * 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 partion(int *a,int left,int right){
    int temp=a[left];
    while(left<right){
        while(left<right&&a[right]>temp) right--;
        a[left]=a[right];
        while(left<right&&a[left]<=temp) left++;
        a[right]=a[left];
    }
    a[left]=temp;
    return left;
}
void quickSort(int *a,int left,int right){
    if(left<right){
        int pos=partion(a,left,right);
        quickSort(a,left,pos-1);
        quickSort(a,pos+1,right);
    }
}

int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
    *returnSize=0;
    int** result=(int**)malloc(sizeof(int *)*(numsSize+1)*6);

    //按照从小到大排序
   quickSort(nums,0,numsSize-1);
   int first,second,third;
   if(numsSize<3) return result;
    
    for(first=0;first<numsSize-2;first++){
        if(nums[first]+nums[first+1]+nums[first+2]>0) break;//此时最小的三个数的和都大于0,没有满足条件的了
        if((first>0)&&nums[first]==nums[first-1]){
            continue;//和上一次枚举的值重复了,跳过此次循环
        }
        for(second=first+1,third=numsSize-1;second<third;){
            if((third)<numsSize-1&&nums[third]==nums[third+1]){
                third--;
                continue;//找到从右往左第一个不同的third,即排除third指针的重复值
            }
            if((second!=(first+1))&&nums[second]==nums[second-1]){
                second++;
                continue;//即排除second指针的重复值
            }
            if((nums[first]+nums[second]+nums[third])>0){
                third--;//大了取个更小的数
            }else if((nums[first]+nums[second]+nums[third])<0){
                second++;//小了取个更大的值
            }else{
                //满足要求
                result[*returnSize]=(int*)malloc(sizeof(int)*3);
                result[*returnSize][0]=nums[first];
                result[*returnSize][1]=nums[second];
                result[*returnSize][2]=nums[third];
                (*returnSize)++;
                second++;
                third--;
            }

        }

    }
    *returnColumnSizes=(int*)malloc(sizeof(int)*(*returnSize));
    for(int i=0;i<*returnSize;i++){
        (*returnColumnSizes)[i]=3;
    }

return result;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值