力扣(LeetCode)15. 三数之和(C++/C语言)

一、环境说明

  1. 本文是 LeetCode 15题 : 三数之和,使用c语言实现。
  2. 快排+对撞指针。
  3. 测试环境:Visual Studio 2019。

二、代码展示

C

//排序,双指针向中间对撞
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** ans = (int**)malloc(sizeof(int*) * numsSize * (numsSize-1)/2);//Cn-2种组合
    *returnSize = 0;//返回值大小从0开始
    *returnColumnSizes = (int*)malloc(sizeof(int) * numsSize * (numsSize-1)/2);//三元组最大数量
    for (int i = 0; i < numsSize; ++i) {
        if (nums[i] > 0) {//剪枝
            break;
        }
        if (i > 0 && nums[i] == nums[i - 1]) {//当前数和上一个数重复,结果重复。
            continue;
        }
        int left = i + 1, right = numsSize - 1;//左指针是第二个数,从第一个数的右一位出发向右; 右指针是第三个数,从右边界向左。
        while (left < right) {//左右不能颠倒
            int sum = nums[left] + nums[right] + nums[i];
            if (sum == 0) {//保存一个答案
                ans[*returnSize] = (int*)malloc(sizeof(int) * 3);
                (*returnColumnSizes)[*returnSize] = 3;
                ans[*returnSize][0] = nums[i];
                ans[*returnSize][1] = nums[left];
                ans[*returnSize][2] = nums[right];
                (*returnSize)++;
                while ((left < right) && (nums[left] == nums[left+1])){//下一个数和当前重复,结果重复。
                    left++;//最后一个重复的数
                }
                left++;//第一个不重复的数
                while ((left < right) && (nums[right] == nums[right-1])){//是上面过程的反向。
                    right--;
                }
                right--;
            }
            else if (sum > 0) {//大了
                right--;
            }
            else {//小了
                left++;
            }
        }
    }
    return ans;
}

C++

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int n = nums.size();
        vector<vector<int>> ans;
        for(int i = 0;i<n-2;i++) {
            if(nums[i]>0) break;//剪枝
            if(i&&nums[i]==nums[i-1]) continue;
            for(int l = i+1,r = n-1;l<r;){
                if(nums[l]==nums[l-1]&&l>i+1) {
                    l++;
                    continue;
                }
                if(nums[i]+nums[l]+nums[r]> 0 )r--;
                else if(nums[i]+nums[l]+nums[r]<0) l++;
                else {
                    ans.push_back({nums[i],nums[l],nums[r]});
                    l++,r--;
                }
            }
        }
        return ans;
    }
};

三、思路分析

  • 如题,无序数组,找三数之和等于 0 0 0。容易想到三重循环,依次确定三个数,得到答案,时间复杂度 O ( n 3 ) O(n^3) O(n3)。考虑问题规模3000,需要 27 × 1 0 9 27\times10^9 27×109次执行,TLE。要降低时间复杂度。
  • 转换思路,我们让这个数组有序,是不是就可以用双指针来解题了呢?答案是肯定的。

3.1 双指针思路:

  1. 快排 n u m s nums nums数组,一次遍历 n u m s nums nums,当前遍历的位置是 i i i
  2. i i i表示第一个数, i i i也是最外层遍历的位置;
  3. l e f t left left表示第二个数, l e f t left left i + 1 i+1 i+1开始往右;
  4. r i g h t right right表示第三个数, r i g h t right right n u m s S i z e − 1 numsSize - 1 numsSize1开始往左。

3.2思路解释:

  1. 三数之和 s u m = n u m s [ i ] + n u m s [ l e f t ] + n u m s [ r i g h t ] sum=nums[i]+nums[left]+nums[right] sum=nums[i]+nums[left]+nums[right]
  2. 对于内层 l e f t left left r i g h t right right的双指针循环, n u m s [ i ] nums[i] nums[i]是固定的。
  3. 如果 s u m > 0 sum>0 sum>0,为了让 s u m sum sum趋于0, r i g h t right right左移一位;
  4. 如果 s u m < 0 sum<0 sum<0,为了让 s u m sum sum趋于0, l e f t left left右移一位。
  • 为了避免重复的三元组,还有额外的操作,见代码和注释。

四、代码分析

  • 理解思路很重要!
  • 博主欢迎读者在评论区留言,作为日更博主,看到就会回复的。

五、AC

力扣(LeetCode)15. 三数之和(C++/C语言)_第1张图片
力扣(LeetCode)15. 三数之和(C++/C语言)_第2张图片

六、复杂度分析

  1. 时间复杂度: O ( n 2 ) O(n^2) O(n2) , n u m s nums nums数组的大小= n n n。快排时间复杂度是 O ( n l o g n ) O(nlogn) O(nlogn)。一次遍历 n u m s nums nums的时间复杂度是 O ( n ) O(n) O(n),使用双指针 l e f t left left r i g h t right right对撞的时间复杂度是 O ( n ) O(n) O(n),二者嵌套的时间复杂度是 O ( n 2 ) O(n^2) O(n2)。实际时间复杂度是 O ( n 2 + n l o g n ) O(n^2+nlogn) O(n2+nlogn)
  2. 空间复杂度: O ( l o g n ) O(logn) O(logn),快排的递归调用压栈 O ( l o g n ) O(logn) O(logn)次,空间复杂度是 O ( l o g n ) O(logn) O(logn)

你可能感兴趣的:(小白leetcode,leetcode,c语言,算法,双指针,c++)