一、博客声明
找工作逃不过刷题,为了更好的督促自己学习以及理解力扣大佬们的解题思路,开辟这个系列来记录。代码可能不是自己写的,不求方法最好,只求更多地理解大佬们的解题思路。
二、题目描述
给你一个整数数组nums
,判断是否存在三元组[nums[i], nums[j], nums[k]]
满足i != j、i != k 且 j != k
,同时还满足nums[i] + nums[j] + nums[k] == 0
。请你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0
。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0
。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0
。
不同的三元组是 [-1,0,1]
和 [-1,-1,2]
。
注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。
示例 3:
输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。
提示:
3 <= nums.length <= 3000
-105 <= nums[i] <= 105
三、解题思路
1、思路说明
这题主要使用双指针的方法来解决,因为有三个数,所以最好先固定一个,然后剩下两个就可以用双指针来进行对向滑动,跟上一个盛水类似。另外一个比较重要的就是排序,这道题目如果在乱序的情况下去做判断的话,就非常麻烦。下面的图更直观。至于怎么判断不重复,因为已经排序了,只要能找到和为0的三个数就有办法判断了,详细可以可以看代码。
2、知识补充
qsort快速排序
因为在这道题目中,因为要求输出不重复的对应数组,如果在原本乱序的数组中去筛选,将特别复杂和耗时。因此需要用到排序。而C语言内部的快速排序方法可以很好的被利用。
所需库: <stdlib.h>
声明:
下面是 qsort() 函数的声明。
void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))
void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))
参数:
base – 指向要排序的数组的第一个元素的指针。
nitems – 由 base 指向的数组中元素的个数。
size – 数组中每个元素的大小,以字节为单位。
compar – 用来比较两个元素的函数方法。
返回值:
该函数不返回任何值,而是将你给定的数组中的元素进行排序。
compar比较函数的书写:
根据比较函数的不同,快速排序方法可以执行升序和降序两种排列方式。
如果是想升序(从小到大)排列,比较函数的写法按照下面这段代码编写。
int cmpfunc (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
如果是想降序(从大到小)排列,比较函数的写法按照下面这段代码编写。
int cmpfunc (const void * a, const void * b)
{
return ( *(int*)b - *(int*)a );
}
示例:
#include <stdio.h>
#include <stdlib.h>
int values[] = { 88, 56, 100, 2, 25 };
int cmpfunc (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
int main()
{
int n;
printf("排序之前的列表:\n");
for( n = 0 ; n < 5; n++ ) {
printf("%d ", values[n]);
}
qsort(values, 5, sizeof(int), cmpfunc);
printf("\n排序之后的列表:\n");
for( n = 0 ; n < 5; n++ ) {
printf("%d ", values[n]);
}
return(0);
}
让我们编译并运行上面的程序,这将产生以下结果:
排序之前的列表:
88 56 100 2 25
排序之后的列表:
2 25 56 88 100
四、解题代码(附注释)
//快速排序的比较函数,这里使用升序(从小到大)
int cmpfunc(const void *a, const void *b){
return (*(int*)a - *(int*)b);
}
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
int left_position = 0; //左边缘的固定位,初始化为0
int sum;
int number = 0; //用于记录返回个数
int **res = malloc(sizeof(int*) * 18000);
qsort(nums, numsSize, sizeof(int), cmpfunc); //进行快速排序--升序
for(left_position; left_position < numsSize - 2; left_position++){
int left = left_position + 1; //移动窗口的左边缘
int right = numsSize - 1; //移动窗口的右边缘
//升序,第一个元素大于0,三数之和必大于0,直接终止循环
if(nums[left_position] > 0){
break;
} else if(nums[left] > 0 && nums[left_position] + nums[left] > 0){ //第二个数大于0,前两个数之和大于0,直接终止循环。
break;
} else {
while(left < right){
sum = nums[left_position] + nums[left] + nums[right];
if(sum == 0){
res[number] = malloc(sizeof(int) * 3);
res[number][0] = nums[left_position];
res[number][1] = nums[left];
res[number][2] = nums[right];
number++;
while (left < right && nums[left] == res[number - 1][1]) left++; // 避免left重复
} else if(sum < 0){
left++;
} else {
right--;
}
}
}
while (left_position + 1 < numsSize && nums[left_position] == nums[left_position + 1]) left_position++; // 避免left_position重复
}
*returnSize = number;
*returnColumnSizes = malloc(sizeof(int) * number);
for (int i = 0; i < number; i++) {
(*returnColumnSizes)[i] = 3;
}
return res;
}