Leetcode-15. 3Sum

Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note:

The solution set must not contain duplicate triplets.

Example:

Given array nums = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

Solution:

  1. 如何找?
    最简单的方法是暴力求解,三层for循环判断nums[i]+nums[j]+nums[k]=0,时间复杂度为O(n^3),由于时间复杂度太高,下面进行优化。

  2. 如何优化?
    可通过先对数组进行从小到大排序,可通过快排,排序时间复杂度为O(nlogn),排好序后,固定一个节点,以固定节点的下一个作为首指针,将数组最后一个节点作为尾指针,左右夹逼推进,若三数之和大于0,则说明尾指针太大,需要前移,若三数之和小于0,说明首指针太小,需要后移,近而通过夹逼获得刚好为0的点或不存在刚好为0的点,依次将固定节点从首节点直至倒数第三个节点即可。

  3. 如何去重?(难点)
    思考:出现重复的情况有2种:
    (1)考虑数组为[-1 -1 0 1],当固定节点在第一个节点时,[-1 -1 0 1]出现[-1 0 1],符合条件,当固定节点往后移动至下一个-1时,我们知道此时后面一定会出现重复:[-1 -1 0 1](加粗部分),则出现重复条件为当前固定节点等于前一个节点,即去重条件为当固定节点非首节点时,判断固定节点不等于前一个节点。
    (2)考虑数组[-1 -1 0 0 1] ,固定节点-1,依次可以得到序列[-1 -1 0 0 1] 和[-1 -1 0 0 1] 此时出现重复,即当首节点往右边移动时,如果满足和为0,如果继续往右移动和当前节点一致时,必然是重复的,即此时去重条件为nums[start]==nums[start+1],start继续后移动,即start++,同理尾节点往前移动和当前节点一致时,去重条件为nums[end]==nums[end-1],尾指针继续前移,end–。

int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){

    //对数组进行排序
    ordernums(nums,numsSize);
    
    //初始化
    int mallocSize = numsSize*(numsSize);
    int** returnArray = (int **)malloc(sizeof(int*)*mallocSize);
    *returnColumnSizes = (int *)malloc(sizeof(int*)*mallocSize);
    *returnSize = 0;
    
    //fix为固定点,依次往后移动至倒数第三个节点
    int sum,start,end;
    
    for (int fix = 0; fix<numsSize-2; fix++) {
    //去重(上文重复条件1)
        if (fix>0 && nums[fix] == nums[fix-1]) {
            continue;
        }
        start = fix + 1;
        end = numsSize - 1;
        while (start < end) {
            sum = nums[start] + nums[end] + nums[fix];
            if (sum==0) {
                returnArray[*returnSize] = (int*)malloc(sizeof(int) * 3); // 每次找到一组,二级指针就分配三个空间
                               (*returnColumnSizes)[*returnSize] = 3; // 记录列数
                               returnArray[*returnSize][0] = nums[fix];
                               returnArray[*returnSize][1] = nums[start];
                               returnArray[*returnSize][2] = nums[end];
                               (*returnSize)++;
                start++;
                end--;
                //去重(上文重复条件2)
                while(start < end && nums[start] == nums[start-1]){
                    start++;
                }
                while (start < end && nums[end] == nums[end+1]) {
                    end--;
                }
            }else if(sum < 0 ) {
                start++;
            }else{
                end--;
            }
        }
    }
    return returnArray;
}

//此时采用冒泡排序 
void ordernums(int* num,int size){
    for (int j = 0; j<size; j++) {
        for (int i = 0; i<size-j-1; i++) {
            if (num[i+1]<num[i]) {
                int temp = num[i];
                num[i] = num[i+1];
                num[i+1] = temp;
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值