每日一题
四数之和
注:
如果大家没做过题目两数之和、三数之和,强烈建议先去做做,也可以参考我之前写的博客,这样做这一题会事半功倍,且由于本题思路和三数之和十分类似,故对于解题思路,也不会过多讲解,有不懂的可以参考三数之和
思路
本题和三数之和思想类似,同样是采用双指针的方法,只是由于多了一个数,因此也要多套一层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;
}