打卡leetcode第5天

1.两数之和--输入有序数组(三种解法)

【题目】

【分析】

 由于之前的是输入无序数组,暴力法参考:打卡刷题leetcode第1天_zcyst的博客-CSDN博客

利用输入数组有序的性质,可以得到时间复杂度和空间复杂度更优的解法。

【法1 二分法+暴力法

 【代码】C

int* twoSum(int* numbers, int numbersSize, int target, int* returnSize)
{

    int * returnNums = (int *)malloc(sizeof(int) * numbersSize);
    //二分查找
    //时间复杂度是 logn
    //题目假设一定有结果
    int i;
    int indexLeft;
    int indexRight ;
    int indexMiddle;
    int temp;

    *returnSize = 2;
    for(int i = 0; i < numbersSize; i++)
    {
        temp = target - numbers[i];

        //每次都是一个二分法
        indexLeft  = i + 1;
        indexRight = numbersSize - 1;
        while(indexLeft <= indexRight)
        {
            indexMiddle = (indexRight - indexLeft)/2 + indexLeft;
            if(numbers[indexMiddle] == temp)
            {
                returnNums[0] = i + 1;
                returnNums[1] = indexMiddle + 1;
                return returnNums;
            }
            if(numbers[indexMiddle] > temp)
            {
                indexRight = indexMiddle - 1;
            }
            else
            {
                indexLeft = indexMiddle + 1;
            }
        }
    }
    //扩展没有结果怎么处理
    *returnSize = 0;
    return returnNums;

}

参考的这个代码比我手敲一遍的时间短很多,咱也不知道为啥

【法2 双指针法

【代码】C

int* twoSum(int* numbers, int numbersSize, int target, int* returnSize)
{

    int * returnNums = (int *)malloc(sizeof(int) * numbersSize);
    //指针查找
    //时间复杂度是 n
    //题目假设一定有结果

    int indexLeft  = 0;
    int indexRight = numbersSize - 1;
    *returnSize = 2;

    while(indexLeft <= indexRight)
    {
        if(target == (numbers[indexLeft] + numbers[indexRight] ))
        {
            returnNums[0] = indexLeft + 1;
            returnNums[1] = indexRight + 1;
            return returnNums;
        }
        else if(target <= (numbers[indexLeft] + numbers[indexRight] ))
        {
            indexRight--;
        }
        else 
        {
            indexLeft++;
        }
    }

    //扩展没有结果怎么处理
    *returnSize = 0;
    return returnNums;

}


速度稍快一些

 【法3 二分+双指针

 【代码】C

int* twoSum(int* numbers, int numbersSize, int target, int* returnSize)
{
    int * returnNums = (int *)malloc(sizeof(int) * numbersSize);
    //二分查找 + 双指针
    //时间复杂度是 logn
    //题目假设一定有结果
    int i;
    int indexLeft;
    int indexRight ;
    int indexMiddle;
    int temp;
    *returnSize = 2;


    indexLeft = 0;
    indexRight = numbersSize - 1;
    while (indexLeft <= indexRight) 
    {
        int temp = numbers[indexLeft] + numbers[indexRight];
        if (temp == target) 
        {
            break;
        } 
        else if (temp < target)
        {
            indexLeft++;
        } 
        else 
        {
            indexRight--;
        }
    }
    returnNums[0] = indexLeft + 1;
    returnNums[1] = indexRight + 1;
    *returnSize = 2;
    return returnNums;

}

这个效率跟上一个差不多,大部分是双指针的思想

 2.三数之和

【题目】

【分析】

【代码】C

int cmp(const void *a,const void *b)
{
    return *(int*)a - *(int*)b;
}

int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes)
{
    *returnSize = 0;
    if(numsSize < 3)
        return NULL;
    qsort(nums,numsSize,sizeof(int),cmp);//快排函数
    int **ans = (int **)malloc(sizeof(int *) * numsSize  *numsSize);
    *returnColumnSizes = (int *)malloc(sizeof(int) * numsSize * numsSize);
    int i,j,k,sum;

    int indexLeft   = 0;
    int indexMiddle = 0;
    int indexRight  = 0;
    //快排过后,使用三指针 遍历
    //左边遍历到倒数第三位即可
    for(indexLeft = 0; indexLeft< numsSize - 2; indexLeft++)
    {
        if(nums[indexLeft] > 0) 
        {
            //因为是快排的结果,所以如果出现大零的
            //后面的值都是大于0的
            return ans;
        }

        //如果值相同 则不需要遍历
        if(indexLeft > 0 && nums[indexLeft] == nums[indexLeft-1])
            continue;
        indexMiddle = indexLeft + 1;
        indexRight  = numsSize - 1;

        //双指遍历 找到所有的可能
        while(indexMiddle < indexRight)
        {
            sum = nums[indexLeft] + nums[indexMiddle] + nums[indexRight];

            if(sum == 0)
            {
                ans[*returnSize] = (int*)malloc(sizeof(int)*3);
                (*returnColumnSizes)[*returnSize] = 3;
                ans[*returnSize][0] = nums[indexLeft];
                ans[*returnSize][1] = nums[indexMiddle];
                ans[*returnSize][2] = nums[indexRight];
                *returnSize += 1;
                //过滤相等的值
                while(indexMiddle < indexRight && nums[indexMiddle] == nums[++indexMiddle]);
                while(indexMiddle < indexRight && nums[indexRight] == nums[--indexRight]);
            }
            else if(sum > 0)
            {
                //左边递减
                indexRight--;
            }
            else
            {
                //右边递增
                indexMiddle++;
            }
        }
    }
    return ans;
}

 注:qsort()函数

 还有其他的比较方式(浮点型)见C语言qsort函数用法_小赵的博客-CSDN博客_qsort函数c语言

3.四数之和

【题目】

【解析】

【代码】C

 int compareFunc(void* a, void* b)
{
    if (*(int*)a >= *(int*)b)
    {
        return 1;
    }
    return -1;
}

int** fourSum(int* nums, int numsSize, int target, int* returnSize, int** returnColumnSizes)
{
    //4数之和转为三数之和的问题。
    //使用双指针
    *returnSize = 0;
    if (numsSize < 4)
        return NULL;

    int **returnNums     = (int**)malloc(sizeof(int*) * numsSize * numsSize);
    *returnColumnSizes   = (int*)malloc(sizeof(int) * numsSize * numsSize);
    qsort(nums, numsSize, sizeof(int), cmp);
    int a , b, c, d;
    long long sum;
    int indexLeft = 0;
    int indexRight = 0;
    for (a = 0; a < numsSize - 3; a++)
    {
        if ((nums[a] > 0) && (nums[a] > target))
        {
            //剪枝 因为存在负数 会越加 越小,所以这里需要判断nums[a] > 0
            //因为是快排的结果,所以如果出现大target的
            //后面的值都是大于target的
            break;
        }
        if (a > 0 && nums[a] == nums[a - 1])
        {
            continue; //去重
        }
        for (b = a + 1; b < numsSize; b++)
        {
            if (( b > a + 1) && (nums[b] == nums[b - 1]) )
            {
                continue; //去重
            }

            if (((nums[a] + nums[b]) > target)  && (nums[b] > 0) )
            {
                //因为是快排的结果,所以如果出现a + b 大于零的
                //后面的b值都是大于target的
                //剪枝
                break;
            }

            //双指针 移动
            indexLeft   =  b + 1;
            indexRight  = numsSize - 1;
            while (indexLeft < indexRight)
            {
                sum = (long)nums[a] + nums[b] + nums[indexLeft] + nums[indexRight];
                if (sum == target)
                {
                    //找到目标
                    (*returnColumnSizes)[*returnSize] = 4;
                    returnNums[*returnSize] = (int*)malloc(sizeof(int) * 4);
                    returnNums[*returnSize][0] = nums[a];
                    returnNums[*returnSize][1] = nums[b];
                    returnNums[*returnSize][2] = nums[indexLeft];
                    returnNums[*returnSize][3] = nums[indexRight];
                    *returnSize = *returnSize + 1;
                    //跳过相同的值
                    while ((indexLeft < indexRight) && nums[indexLeft] == nums[indexLeft + 1])
                    {
                        indexLeft++;
                    }

                    while ((indexLeft < indexRight) && nums[indexRight] == nums[indexRight - 1])
                    {
                        indexRight--;
                    }

                    indexLeft++;
                    indexRight--;
                }
                else if (sum < target)
                {
                    indexLeft++;
                }
                else if (sum > target)
                {
                    indexRight--;
                }
            }
            
        }
    }
    return returnNums;
}

 另一种代码,觉得写的也很好,把快排写进去了

int partition(int *nums,int low,int high){
    int pivot=nums[low];
    while (low<high){
        while (nums[high]>=pivot&&low<high)
            high--;
        nums[low]=nums[high];
        while (nums[low]<=pivot&&low<high)
            low++;
        nums[high]=nums[low];
    }
    nums[low]=pivot;
    return low;
}

void quick_sort(int *nums,int low,int high){
    int pivot;
    if (low<high){
        pivot=partition(nums,low,high);
        quick_sort(nums,low,pivot-1);
        quick_sort(nums,pivot+1,high);
    }
}

int** fourSum(int* nums, int numsSize, int target, int* returnSize, int** returnColumnSizes){
    quick_sort(nums,0,numsSize-1);
    int **ans=(int **)malloc(sizeof(int *)*numsSize*6);
    int key1,key2,i,j;

    *returnColumnSizes =(int *)malloc(sizeof(int) *numsSize*6);
    *returnSize=0;

    for(key1=0;key1<numsSize;key1++){ 
        if (key1>0&&nums[key1]==nums[key1-1])//key1去重
            continue;
        for(key2=key1+1;key2<numsSize;key2++){
            if (key2>key1+1&&nums[key2]==nums[key2-1])//key2去重
                continue;
            i=key2+1;
            j=numsSize-1;
            while(i<j){
                if(nums[key1]+nums[key2] + nums[i] + nums[j]==target){
                    ans[*returnSize]=(int *)malloc(sizeof(int)*4);
                    ans[*returnSize][0]=nums[key1];
                    ans[*returnSize][1]=nums[key2];
                    ans[*returnSize][2]=nums[i];
                    ans[*returnSize][3]=nums[j];
                    returnColumnSizes[0][*returnSize]=4;
                    (*returnSize)++;//*returnSize别忘了加括号
                    while(i<j&&nums[i]==nums[i+1]) 
                        i++;//去重
                    while(i<j&&nums[j]==nums[j-1]) 
                        j--;//去重
                    i++;
                    j--;
                }
                else if(nums[key1]+nums[key2] + nums[i] + nums[j]>target) 
                    j--;
                else 
                    i++;
            }
        }
    }
    return ans;
}

 

 

参考:力扣

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值