每日一题——四数之和(双指针解法)

每日一题

四数之和

在这里插入图片描述

注:

如果大家没做过题目两数之和三数之和,强烈建议先去做做,也可以参考我之前写的博客,这样做这一题会事半功倍,且由于本题思路和三数之和十分类似,故对于解题思路,也不会过多讲解,有不懂的可以参考三数之和

思路

  • 本题和三数之和思想类似,同样是采用双指针的方法,只是由于多了一个数,因此也要多套一层for循环

  • 同样,我们要先保证数组有序,因此首先就要对数组进行排序

  • 在《三数之和》中,我们使用一层for循环来遍历数组(相当于先确定第一个数a的值),然后再利用双指针right和left确定另外两个数b,c的值,然后再用a + b + c和target比较,从而确定结果集

    for(i = 0; i < numsSize; i++)
    {
        int left = i + 1;
        int right = numsSize - 1;
        while(left < right)
        {
            int sum = nums[i] + nums[left] + nums[right];
            if(sum > 0)
                right--;
            else if(sum < 0)
                left++;
            else
            {
    			//存入数据
            }
        }
    }
    
  • 而在《四数之和》中,由于多了一个数,那么我们就要先确定两个数的值a,b,然后再利用双指针right和left确定另外两个数b,c的值,最后再用四数之和sum和target比较,确定结果集**

    for(int i = 0; i < numsSize; i++)
    {
        for(int j = i + 1; j < numsSize; j++)
        {
            int left = j + 1, right = numsSize - 1;
            while(left < right)
            {
                //为防止溢出,故要做出相应处理
                long long sum = (long long)nums[i] + nums[j] + nums[left] + nums[right];
                if(sum > target)
                    right--;
                else if(sum < target)
                    left++;
                else
                {
                    //存入数据
                }
            }
        }
    }
    
  • 关于去重的处理,和《三数之和》类似,故不再赘述

    for(int i = 0; i < numsSize; i++)
    {
        //a的去重
        if(i > 0 && nums[i] == nums[i - 1])
            continue;
    
        for(int j = i + 1; j < numsSize; j++)
        {
            //b的去重
            if(j > i + 1 && nums[j] == nums[j - 1])
                continue;
    
            int left = j + 1, right = numsSize - 1;
            while(left < right)
            {
                long long sum = (long long)nums[i] + nums[j] + nums[left] + nums[right];
                if(sum > target)
                    right--;
                else if(sum < target)
                    left++;
                else
                {
                    //存入数据
    
                    //c,d的去重
                    while(left < right && nums[left] == nums[++left]);
                    while(left < right && nums[right] == nums[--right]);
    
                }
            }
        }
    }
    

实现代码

/**
 * 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().
 */

//排序算法
void Sort(int *nums, int numsSize)
{
    for(int i = 0; i < numsSize - 1; i++)
    {
        int flag = 0; 
        for(int j = 0; j < numsSize - 1 - i; j++)
        {
            if(nums[j] > nums[j + 1])
            {
                flag = 1;
                int temp = nums[j];
                nums[j] = nums[j + 1];
                nums[j + 1] = temp;
            }
        }
        if(!flag)
            return;
    }
}

int** fourSum(int* nums, int numsSize, int target, int* returnSize, int** returnColumnSizes){
    //排序
    Sort(nums, numsSize);
    
    //设定最多有100组四元组
    int base = 100;
    
    //分配内存
    int **arr = (int **)malloc(sizeof(int *) * base);
    *returnColumnSizes = (int *)malloc(sizeof(int) * base);
    
    //四元组的初始值为0
    *returnSize = 0;

    for(int i = 0; i < numsSize; i++)
    {
        //如果第一个数就大于target且第一个数大于等于0,那么四数之和肯定大于target,直接break
        if(nums[i] > target && nums[i] >= 0)
            break;
        
        //a的去重
        if(i > 0 && nums[i] == nums[i - 1])
            continue;
        
        for(int j = i + 1; j < numsSize; j++)
        {
            //如果(a + b > target)且(a + b >= 0),那么四数之和肯定大于target,直接break
            if((long long)nums[i] + nums[j] > target && (long long)nums[i] + nums[j] >= 0)
                break;
            
            //b的去重
            if(j > i + 1 && nums[j] == nums[j - 1])
                continue;
            
            int left = j + 1, right = numsSize - 1;
            while(left < right)
            {
                //为防止整形溢出,故要将sum定义为long long
                long long sum = (long long)nums[i] + nums[j] + nums[left] + nums[right];
                
                if(sum > target)
                    right--;
                else if(sum < target)
                    left++;
                else
                {
                    //为存储四元组的数组分配内存
                    arr[*returnSize] = (int *)malloc(sizeof(int) * 4);
                    (*returnColumnSizes)[*returnSize] = 4;
					
                    //存入数据
                    arr[*returnSize][0] = nums[i];
                    arr[*returnSize][1] = nums[j];
                    arr[*returnSize][2] = nums[left];
                    arr[*returnSize][3] = nums[right];
                    
                    //四元组个数加一
                    (*returnSize)++;
					
                    //c,d去重
                    while(left < right && nums[left] == nums[++left]);
                    while(left < right && nums[right] == nums[--right]);

                }
                
                //如果四元组个数达到初始最大值,那就要进行扩容
                if((*returnSize) == base)
                {
                    base *= 2;
                    arr = (int **)realloc(arr,sizeof(int *) * base);
                    *returnColumnSizes = (int *)realloc(*returnColumnSizes,sizeof(int) * base);
                }
            }
        }
    }
    
    //返回存储四元组的二维数组
    return arr;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Forward♞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值