leetcode-15.三数之和-20220821

  1. 三数之和
    给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:

输入:nums = []
输出:[]
示例 3:

输入:nums = [0]
输出:[]

提示:
0 <= nums.length <= 3000
-105 <= nums[i] <= 105

思考:这个题目是我参考 卡神的做法做出来的,具体网址 https://www.programmercarl.com/ 在这个里面

首先哈希表的方法可以求出来所有的三元组,但是去重的难度非常大

使用双指针的方法,可以将算法的时间复杂度降低一个数量级,对代码的效率提升很高

上代码~

/**
 * 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().
 */
 // 这个题目使用双指针方法进行求解
 // 1、数组进行排序
 // 2、对于 a,选择从开头到结尾进行尝试
 // 3、对b和c,选择从a的后面一个位置和数组的最后一个位置进行查找
 // 4、如果a+b+c>0 说明整体比较大,那么就将c向左移动
 // 5、如果a+b+c<0 说明整体比较小,那么将b向右移动
 // 6、如果a+b+c=0 说明正好是结果,那么输出结果即可 此时b和c都要进行移动,缩小范围

// 那对结果的去重应该如何进行呢?

void quicksort(int* nums, int left, int right)
{
    if (left > right) return;
    int mid = partition(nums, left, right);
    quicksort(nums, left, mid - 1);
    quicksort(nums, mid+1, right);
}


int partition(int* nums, int left, int right)
{
    int key = nums[left];
    int first = left;
    int last = right;
    int tmp;
    while(first < last) {
        //先找右边第一个小于key的值的位置
        while(first<last && nums[last] >= key) {
            last--;
        }
        // 再找左边第一个大于key的值的位置
        while(first<last && nums[first] <= key) {
            first++;
        }
        // 交换上面两个数的位置
        if (first < last) {
            tmp = nums[first];
            nums[first] = nums[last];
            nums[last] = tmp;
        }
    }
    // 交换key的位置
    tmp = nums[left];
    nums[left] = nums[first];
    nums[first] = tmp;
    return last;
}

int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
    quicksort(nums, 0, numsSize - 1);
    int** ans = (int**)malloc(sizeof(int*) * 18000);
    *returnSize = 0; // 多少个符合条件的三元组
    int* col = (int*)malloc(sizeof(int) * 18000);
    *returnColumnSizes = col;
    int a, b, c;
    for (a = 0; a < numsSize - 2; a++) {
        // 对a去重剪枝
        if (nums[a] > 0) break;
        if(a > 0 && nums[a] == nums[a - 1]) {
            continue;
        }
        b = a + 1;
        c = numsSize - 1;
        while(b < c) {
            if (nums[a] + nums[b] + nums[c] < 0) {
                b++;
            }else if (nums[a] + nums[b] + nums[c] > 0) {
                c--;
            } else { // 得到的答案
                // 获取答案 当nums[a] + nums[b] + nums[c] = 0
                ans[*returnSize] = (int*)malloc(sizeof(int) * 3);
                ans[*returnSize][0] = nums[a];
                ans[*returnSize][1] = nums[b];
                ans[*returnSize][2] = nums[c];
                col[*returnSize] = 3;
                (*returnSize)++;
                // 对b和c的去重
                while (b < c && nums[c] == nums[c - 1]) c--;
                while(b < c && nums[b] == nums[b + 1]) b++;
                b++; // 关键一步,忘了处理了
                c--;
            } 
        }
    }
    return ans;
}

总结:
1、对基础算法的实现不熟悉,一个快速排序写了半个小时,最后还是参考人家的实现写出来的,后面多用多练
2、对算法的每个步骤细节没有写清楚,收集答案那块忘了收缩了,然后搞得b和c没有刷新,同时对去重的考虑也不清楚,大脑是混乱的,所以后面写程序的时候所有的步骤实现都写出来,然后再写代码,这样调试的时候会比较快速

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值