leetcode复盘:15.三数之和
题目描述:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
一、个人小结:
(1)排序:由于不能包含重复的三元组,需要先对数组进行排序;排序时可以使用C中自带的qsort方法,排序常用代码如下:
int cmp(const void *a, const void *b)
{
//从小到大排序
return *(int*)a - *(int*)b;
}
//nums为数组名,numsize为数组大小,cmp为比较函数
//高级做法,可以比较结构体中的数据
qsort(nums, numsSize, sizeof(int), cmp);
(2)内存申请(二位数组):malloc函数,入参为申请内存大小,赋值前一般强制转化成目标类型,比如一次指针或二次指针。
一维数组内存申请:
int *arrOne = (int*)malloc(arrOneSize * sizeof(int));
注:arrOne为一次指针类型,则malloc自然强制转化成一次指针类型,arrOne为int型指针,每个元素大小为sizeof(int),且共有arrOneSize个元素,所有内存申请大小为(arrOneSize * sizeof(int)),其单位为字节。
二维数组内存申请:
int **arrTwo = (int**)malloc(arrTwoSize * sizeof(int *));
注:
(a)与一位数组内存申请如出一辙,只不过arrTwo为二次指针,即指向指针的指针,即*arrTwo或者arrTwo[0]仍然是一个指针;
(b)申请完以上内存后,arrTwo指向的一片内存中,一共可以存放arrTwoSize个int型的指针,所以其大小为(arrTwoSize * sizeof(int *)),单位为字节;
(c)申请完以上内存后,只能存放几个地址,还不能存放用户数据,所有可以针对每个指针,再次申请存放数据的内存:
int arrTwo[0] = (int *)malloc(arrTwoSize0 * sizeof(int));
int arrTwo[1] = (int *)malloc(arrTwoSize1 * sizeof(int));
int arrTwo[2] = (int *)malloc(arrTwoSize2 * sizeof(int));
int arrTwo[3] = (int *)malloc(arrTwoSize3 * sizeof(int));
(d)arrTwo[0]、arrTwo[1]、arrTwo[2]、arrTwo[3]均为指针,其值存放在第一次为arrTwo申请的内存中,这样的指针一共由arrTwoSize个;而现在arrTwo[0]指向了一片新申请的内存,其中可以存放(arrTwoSize0 * sizeof(int))这么多字节的数据,至此,就完成了二维数组的申请
二:解题过程
解题参考 画家王铁男:https://leetcode-cn.com/problems/3sum/solution/chun-c-kuai-pai-shuang-zhi-zhen-by-hua-jia-wang-ti/
(1)先将数组排序;求三数之和,可以先固定一个数,然后求其他两个数;固定当前数后,使用双指针法,一头一尾逐步搜索, 逼近;
(2)本题中,一个大坑在于对returnColumnSizes的处理,该变量实际上使用个一维指针就可以,偏偏要用个二维指针,其实是在当一维指针用,用于存储每个返回数组的长度,其实冗余,题意中已经明确返回数组长度为3,强行提高题目难度;
(3)变量去重,是本题的难点,在数组排序后,遍历cur、low、high时,需要考虑重复;去重操作是本题的精髓所在;在确定cur时,需要针对low、high去重;在遍历cur时,需要对cur去重
/**
* 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().
*/
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 **threeNum = (int**)malloc(6 * numsSize * sizeof(int *));
//实际上使用个一维指针就可以,偏偏要用个二维指针,其实是在当一维指针用
*returnColumnSizes = (int*)malloc(6 * numsSize * sizeof(int));
int cur = 0;
int low = cur + 1;
int high = numsSize - 1;
while ((nums[cur] <= 0) && (cur < numsSize - 2)) {
low = cur + 1;
high = numsSize - 1;
while (low < high) {
if (nums[cur] + nums[low] + nums[high] == 0) {
threeNum[*returnSize] = (int*)malloc(3*sizeof(int));
//(*returnColumnSizes)[*returnSize] = 3;
returnColumnSizes[0][*returnSize] = 3;
threeNum[*returnSize][0] = nums[cur];
threeNum[*returnSize][1] = nums[low];
threeNum[*returnSize][2] = nums[high];
(*returnSize)++;
//lowhigh 去重
while((nums[low] == nums[++low]) && (low < high)){
}
while((nums[high] == nums[--high]) && (low < high)){
}
} else if (nums[cur] + nums[low] + nums[high] > 0) {
high--;
} else {
low++;
}
}
//cur去重
while((nums[cur] == nums[++cur]) && (cur < numsSize - 2)){
}
}
return threeNum;
}