一、题目
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
二、题解
思路为:
-
当输入size < 3 时,直接返回空
-
当输入size >=3时,分配内存
n * ( n-1 ) / 6
假设所有的数相加都等于0
,n
个数,每三个数一组,共有n-2 + n-3 + n-4 + ....+ 1
种情况,共n * ( n-1 ) / 2
种,但在这种情况下是不可能的。因为题目要求不可重复。
所以,取的值 比(size-1)*(size-2)/2
小就可以。
考虑到,当 输出size 为 3 时,n * ( n-1 ) = 6
, 所以被除数最大为 6
所以此处,分配内存大小为n * ( n-1 ) / 6
-
设立三个指针,current, left, right
current 取值范围为[0, size-2]
left 及 right 的取值范围为[ current, size-2]
,left++
,right--
, 当left >= right
时该轮遍历结束 -
排除一些错误解,由于 current 是最小的,right 是最大的
当current >=0
时,最终结果肯定 > 0
当right <=0
时,最终结果肯定 < 0
三个指针移动过程如下图:
// 排序,从小到大排序, 双向排序
void sort_array(int *nums, int numsSize)
{
// 定义左右指针
int *left = nums; // 左
int *p;
int *right = nums + numsSize - 1; // 右
int tmp, *p_tmp;
// 排序前打印数组
printf("排序前:");
for(tmp = 0; tmp < numsSize; tmp++)
printf(" %3d ", nums[tmp]);
printf("\n");
while(left <= right){
p = left;
while( p <= right )
{
if(*left > *p || *p > *right){
p_tmp = *left > *p ? left : right;
tmp = *p;
*p = *p_tmp;
*p_tmp = tmp;
}
p++;
}
left++; right--;
}
printf("排序后:");
for(tmp = 0; tmp < numsSize; tmp++)
printf(" %3d ", nums[tmp]);
printf("\n");
}
/**
* 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** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
int *left, *current, *right, **returen_array;
int i = 0;
*returnSize = 0;
// 当空组内容不合规时,直接返回空
if(numsSize < 3){
return NULL;
}
// 分配内存
returen_array = (int **)malloc(sizeof(int *) * (numsSize - 1) * (numsSize ) / 6 ); // 记录数组大小,array[i][j]中的 i
*returnColumnSizes = (int *)malloc( sizeof(int) * (numsSize - 1) * (numsSize ) / 6 );// 记录每个元素的大小,array[i][j]中的 j
// 对数组进行排序
sort_array(nums, numsSize);
// 思路就是 current,指向开头,
current = nums;
while(current < nums + numsSize -2 && *current <= 0){ // 如果 *current 大于0 时,不用计算了,总值肯定 >0
left = current+1;
right = nums + numsSize -1;
while(left < right && *right >= 0){ // 如果 *right 小于0时,不用计算了,总值肯定 <0
// 当输入数据很多时,开启log 会报错 超出输出限制,此时注释log即可
//printf("第 %d 轮 current=%d, left=%d , right=%d, -- *returensize=%d \n",
//current - nums, *current, *left, *right, *returnSize);
if( *left + *current + *right == 0)
{
// 每找到一组,就动态分配内存
*(returen_array + *returnSize) = (int *)malloc(sizeof(int) * 3);
returen_array[*returnSize][0] = *left;
returen_array[*returnSize][1] = *current;
returen_array[*returnSize][2] = *right;
(*returnColumnSizes)[*returnSize] = 3;
(*returnSize)++;
while( *left == *(++left) && left < right ); // 去重
while( *right == *(--right) && left < right ); // 去重
}else if( *left + *current + *right < 0 ){
left++;
}else{
right--;
}
}
while(*(++current) == *(current-1) && current < nums + numsSize -1 ); // current 去重
}
return returen_array;
}
运行结果如下:
排序前: -1 0 1 2 -1 -4
排序后: -4 -1 -1 0 1 2
第 0 轮 current=-4, left=-1 , right=2, -- *returensize=0
第 0 轮 current=-4, left=-1 , right=2, -- *returensize=0
第 0 轮 current=-4, left=0 , right=2, -- *returensize=0
第 0 轮 current=-4, left=1 , right=2, -- *returensize=0
第 1 轮 current=-1, left=-1 , right=2, -- *returensize=0
第 1 轮 current=-1, left=0 , right=1, -- *returensize=1
第 3 轮 current=0, left=1 , right=2, -- *returensize=2
输出: [[-1,-1,2],[0,-1,1]]
三、leetcode 中 超出输出限制 错误解析
原因为打印的log 太多,此时注释相关重复的printf log 即可。