【LeetCode】
N个数之和问题
一, N个数之和问题
- 三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
一般我们是想到排列组合 列举有多少个组合
如果需要再找个上面优化,需要排除一些重复的组合,找个怎么做呢!
通常我们会排序后, 找出重复的数据比较容易
下面给出 先排序后 再找出不重复的数据 来计算比较容易的
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int compare (const void *a ,const void *b)
{
int *aa=(int * ) a,*bb = (int * )b;
if( * aa >* bb)
{
return 1;
}
if( * aa == * bb)
{
return 0;
}
if( * aa < *bb)
{
return -1;
}
return 0;
}
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes)
{
*returnSize = 0;
if (nums == NULL || numsSize < 3 )
{
return NULL;
}
int alloc_size = 1;
int* *arrayy = malloc(alloc_size * sizeof(int*));
*returnColumnSizes = malloc(alloc_size * sizeof(int));
qsort(&nums[0] , numsSize, sizeof(int), compare);
int array_index = 0;
int b = 0;
int c = 0;
for (int a = 0; a < numsSize; ++a)
{
if (a == 0 || a > 0 && nums[a] != nums[a-1])
{
b = a + 1;
c = numsSize - 1;
while (b < c)
{
int diff = nums[a] + nums[b];
//这里数组是排序过的所以比较容易排除重复的数据 和 不符合要的数据
if ( diff + nums[c] > 0) // 比较大小来看这个数组中还有没有数字
{
while (--c > b && nums[c] == nums[c+1]){}
}
else if (diff + nums[c] < 0)
{
while (++b < c && nums[b] == nums[b-1]){}
}
else
{
(*returnColumnSizes)[ *returnSize] =3;
arrayy[ *returnSize] = malloc(3 * sizeof(int));
arrayy[ *returnSize][0] = nums[a];
arrayy[ *returnSize][1] = nums[b];
arrayy[ *returnSize][2] = nums[c];
(*returnSize)++;
while (--c > b && nums[c] == nums[c+1]){}
while (++b < c && nums[b] == nums[b-1]){}
//内存不足时扩容 2倍扩大
if (*returnSize == alloc_size)
{
alloc_size = 2 * alloc_size;
arrayy = realloc(arrayy, alloc_size* sizeof(int*));
(*returnColumnSizes) = realloc((*returnColumnSizes), alloc_size* sizeof(int));
}
}
}
}
}
return arrayy;
}
int main(int argc, char *argv[])
{
int array[] = { -1, 0, 1, 2, -1, -4 };// {0, 0, 0, 0};
int retsize = 0;
int * retclomueesize = NULL;
int ** retarray = threeSum(&array[0], 10, &retsize, &retclomueesize);
for (int i = 0; i < retsize; ++i)
{
printf("[%d][%d][%d]\n", retarray[i][0], retarray[i][1], retarray[i][2]);
}
return 0;
}
二, 最接近的三数之和
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
示例:
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
提示:
3 <= nums.length <= 10^3
-10^3 <= nums[i] <= 10^3
-10^4 <= target <= 10^4
找个最接近某个数在我们数组上就有绝对值
|nums[1] + nums[ 2] + nums[3] - target|
所以我们就使用abs函数
int compare(const void *a, const void *b)
{
int *aa = (int *)a, *bb = (int *)b;
if (*aa > * bb)
{
return 1;
}
if (*aa == *bb)
{
return 0;
}
if (*aa < *bb)
{
return -1;
}
return 0;
}
int threeSumClosest(int* nums, int numsSize, int target)
{
int min_diff = 0X7FFFFF;
if (nums == NULL || numsSize < 3)
{
return min_diff;
}
qsort(&nums[0], numsSize, sizeof(int), compare);
for (int a = 0; a < numsSize - 2; ++a)
{
int b = a + 1;
int c = numsSize - 1;
while (b < c)
{
int diff = nums[a] + nums[b] + nums[c] - target;
// 绝对值比较
if (abs(diff) < abs(min_diff))
{
min_diff = diff;
}
if (diff < 0)
{
while (++b < c && nums[b] == nums[b - 1]) {}
}
else if (diff > 0)
{
while (b < --c && nums[c] == nums[c + 1]) {}
}
else
{
return target;
}
}
}
return target + min_diff;
}
int main(int argc, char *argv[])
{
int array[] = { -1,2,1,-4 };
printf("sum = %d\n", threeSumClosest(&array[0], 4, 1));
return 0;
}
三,总结:
- 几个数中的最小或者最大值 , 就是使用排列组合,
- 去除重复的数据就需要对数据进行排序 找出过滤重复组合