文章目录
题目描述
Given an array nums of n integers and an integer target, are there elements a, b, c, and d in nums such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.
现给一个n个整数的整型数组和一个整型的目标数,在整型数组中是否存在着的这样的四个数a,b,c,d,四者相加为整型目标数?在数组中,找到所有的和为整型目标数的不同的组
Note:
The solution set must not contain duplicate quadruplets.
结果的集合种的不可以包含重复的组合
Example:
Given array nums = [1, 0, -1, 0, -2, 2], and target = 0.
A solution set is:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]
方法一、BruteForce
思路分析
* 主要是模仿3Sum的解决办法
* 先对的整个数列进行排序的,同时确定a,b,c和d的的相对位置,减少重复元素的出现
* 再者,用两重循环,最外层的循环确定的a的值,第二层循环确定的b的值,然后第二层循环的内部采用解决2sum的two pinter方法
* 何为two pinter方法:
* 确定两个边left和right,left + eright = target,left和right分别从数组的左右两端开始的遍历,left从左往右,即从小往大开始遍历。right从右往左开始遍历,即从大往小。根据left + right的值和target的关系进行判定
* 如果left + right > target,说明需要变小,那就移动right
* 如果left + right <target,说明需要变大,那就移动left
##### C语言实现
/**
* 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 bubble(int *nums , int numSize)
{
int temp;
for(int i = 0;i < numSize - 1;i ++)
{
for(int j = i + 1;j < numSize;j ++)
{
if(nums[i] > nums[j])
{
temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
}
}
int** fourSum(int* nums, int numsSize, int target, int* returnSize, int** returnColumnSizes)
{
int **result ;
result = malloc(sizeof(int*)*1);
(*returnColumnSizes) = malloc(sizeof(int)*1);
if(nums == NULL || numsSize <= 0)
{
*returnSize = 0;
*returnColumnSizes = NULL;
return NULL;
}
bubble(nums,numsSize);
int left = 0,right = 0 ;
*returnSize = 0;
for(int i = 0; i < numsSize ; i ++) {
for(int j = i + 1; j < numsSize; j ++) {
left = j + 1,right = numsSize - 1;
while(left < right) {
if(nums[left] + nums[right] == target - nums[i] - nums[j]) {
result[*returnSize] = malloc(sizeof(int) * 4);
result[*returnSize][0] = nums[i];
result[*returnSize][1] = nums[j];
result[*returnSize][2] = nums[left];
result[*returnSize][3] = nums[right];
(*returnColumnSizes)[*returnSize] = 4;
(*returnSize) ++;
//这里的申请函数好像并没有任何的作用
result = realloc(result,sizeof(int*)*(*returnSize + 1));
(*returnColumnSizes)=realloc(*returnColumnSizes,sizeof(int)*(*returnSize+1));
do
{
left++;
}while(left < numsSize && nums[left] == nums[left - 1]);
} else if(nums[left] + nums[right] < target - nums[i] - nums[j]) {
left ++;
} else {
right --;
}
}
while(j + 1 < numsSize && nums[j] == nums[j + 1])
{
j ++;
}
}
while(i + 1 < numsSize && nums[i] == nums[i + 1])
{
i ++;
}
}
return result;
}
完整的测试代码
#include <stdio.h>
#include <stdlib.h>
int** fourSum(int *nums, int numSize,int target,int *returnSize,int **returnColumnSizes);
void bubble(int nums[],int numSize);
int main()
{
int nums[] = {
-497,-494,-484,-477,-453,-453,-444,-442,-428,-420,-401,-393,-392,-381,-357,-357,-327,-323,-306,-285,-284,-263,-262,-254,-243,-234,-208,-170,-166,-162,-158,-136,-133,-130,-119,-114,-101,-100,-86,-66,-65,-6,1,3,4,11,69,77,78,107,108,108,121,123,136,137,151,153,155,166,170,175,179,211,230,251,255,266,288,306,308,310,314,321,322,331,333,334,347,349,356,357,360,361,361,367,375,378,387,387,408,414,421,435,439,440,441,470,492};
int numSize = 99;
int target = 1682;
int returnSize = 0;
int *returnColumnSize =NULL;
int **result = fourSum(nums,numSize,target,&returnSize,&returnColumnSize);
printf("---------------------------------------------\n");
for(int i = 0;i < returnSize;i ++)
{
printf("%d ",returnColumnSize[i]);
}
printf("\n");
for(int i = 0;i < returnSize;i ++)
{
for(int j = 0;j < 4;j ++)
{
printf("%d ",*(*(result+i)+j));
}
printf("\n");
}
printf("Hello world!\n");
return 0;
}
/**
* 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 bubble(int *nums , int numSize)
{
int temp;
for(int i = 0;i < numSize - 1;i ++)
{
for(int j = i + 1;j < numSize;j ++)
{
if(nums[i] > nums[j])
{
temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
}
}
int** fourSum(int* nums, int numsSize, int target, int* returnSize, int** returnColumnSizes)
{
int **result ;
result = malloc(sizeof(int*)*1);
(*returnColumnSizes) = malloc(sizeof(int)*1);
if(nums == NULL || numsSize == 0)
{
*returnSize = 0;
*returnColumnSizes = NULL;
return NULL;
}
bubble(nums,numsSize);
int left = 0,right = 0 ;
*returnSize = 0;
for(int i = 0; i < numsSize ; i ++) {
for(int j = i + 1; j < numsSize; j ++) {
left = j + 1,right = numsSize - 1;
while(left < right) {
printf("left:%d \n",nums[left]);
printf("right:%d \n",nums[right]);
if(nums[left] + nums[right] == target - nums[i] - nums[j]) {
result[*returnSize] = malloc(sizeof(int) * 4);
result[*returnSize][0] = nums[i];
result[*returnSize][1] = nums[j];
result[*returnSize][2] = nums[left];
result[*returnSize][3] = nums[right];
(*returnColumnSizes)[*returnSize] = 4;
(*returnSize) ++;
//这里的申请函数好像并没有任何的作用
result = realloc(result,sizeof(int*)*(*returnSize + 1));
(*returnColumnSizes)=realloc(*returnColumnSizes,sizeof(int)*(*returnSize+1));
do
{
left++;
}while(left < numsSize && nums[left] == nums[left - 1]);
} else if(nums[left] + nums[right] < target - nums[i] - nums[j]) {
left ++;
} else {
right --;
}
}
while(j + 1 < numsSize && nums[j] == nums[j + 1])
{
j ++;
}
}
while(i + 1 < numsSize && nums[i] == nums[i + 1])
{
i ++;
}
}
return result;
}
分析与总结
- C语言并没有那么多的数据结构的,很多的数据结构的都需要自己写。在本题中的,在函数中申请一个二维数组,还需要是动态的,因为并不知道随机传入的数组到底会构成几组答案。
returnColumnSize到底是啥
- 题目中的给定的传入参数的比较迷惑,经历好一番功夫才明白并获得解答
int** fourSum(int *nums, int numSize,int target,int *returnSize,int **returnColumnSizes);
* 因为答案是一个二维的数组
* 行数通过整数eturnSize确定,是一个确定的整数,所以传入在main函数中声明的整型数returnSize的地址即可
* 每一行的列数不一样,需要一个一维数组确定,但是一维数组的长度又是由行数确定,但是行数不确定,所以在main函数的传入一个空的声明过的一维数组的指针,将该指针的地址传入函数,在函数中为其声明空间
- 关于指针的解引用和自增自减运算符优先级没有分情。本质上来说,自增自减的优先级一定高于指针的解引用。
//++在后
int *p;
*p ++;
*(p++);
//先是返回*p的值,在对指针p进行的++操作
(*p)++;
//先返回*p的值,在对*p的值进行++操作
++*p;
++(*p);
//先将的*p的值++,然后再返回加了之后的值
- 关于指针的解引用和数组调用元素操作的优先级!
*returnColumnSize[0] = 1;
//注意这里写错了,先进行returnColumnSize[0]操作,在进行的解引用,这是一堆乱码
(*returnColumnSize)[0] = 1;
//正确的应该是这样写,本身传入的就是指针的指针
错误处理
- 原因:函数返回的指针地址指向函数内部的地址,在函数退出的时候的,数组的存储空间会被销毁,此时再去访问这个地址就会出现错误
- 常规处理方法:
- 返回的指针提前分配空间
- 用static修饰变量,使之静态存储区的变量
- 使用全局变量
- 解决代码:即使返回的是的空数组,但是没有将的别的一些标识量进行的指定,如returnSize = 0;returnColumnSizes没有将之设置为空
if(nums == NULL || numsSize == 0)
{
*returnSize = 0;
*returnColumnSizes = NULL;
return NULL;
}
- 完成这道题,经历很多的波折,光是参数的理解就花费了很多的时间,除此之外,在很多的两边法消除重复元素上也有很多的疏漏,总结出如下的几条原则
- 凡是指针的解引用和别的符号相混杂使用的,一定要在指针的解引用上方加上括号
- 只要涉及到数组索引的使用,一定要进行的要提前判定的,这个数组有没有越界
方法二、Recursion实现普遍问题
思路分析
- 首先针对的这一类问题,可能会出现5sum,6sum。。。。等一系列的问题,故而关键在于如何书写一个解决这一类的问题的方法
- 参考一下3sum是在2sum外岑提前讨一个循环,4sum无非就是在3sum外层嵌套一个循环,因此nsum就是在n-1sum外层嵌套循环,所以采用递归来处理这个问题
python代码实现
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
def kSum(nums: List[int], target: int, k: int) -> List[List[int]]:
res = []
if len(nums) == 0 or nums[0] * k > target or target > nums[-1] * k:
return res
if k == 2:
return twoSum(nums, target)
for i in range(len(nums)):
if i == 0 or nums[i - 1] != nums[i]:
for _, set in enumerate(kSum(nums[i + 1:], target - nums[i], k - 1)):
res.append([nums[i]] + set)
return res
def twoSum(nums: List[int], target: int) -> List[List[int]]:
res = []
lo, hi = 0, len(nums) - 1
while (lo < hi):
sum = nums[lo] + nums[hi]
if sum < target or (lo > 0 and nums[lo] == nums[lo - 1]):
lo += 1
elif sum > target or (hi < len(nums) - 1 and nums[hi] == nums[hi + 1]):
hi -= 1
else:
res.append([nums[lo], nums[hi]])
lo += 1
hi -= 1
return res
nums.sort()
return kSum(nums, target, 4)
分析与总结
- 有很多的细微独到之处值得学习,已经将问题进行了最简化的处理,排除很多的不必要的情况。同时这样的方式由具有普遍性的,是一个质得学习的好方法