Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
- Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
- The solution set must not contain duplicate triplets.
For example, given array S = {-1 0 1 2 -1 -4}, A solution set is: (-1, 0, 1) (-1, -1, 2)
这道题有个难点,不能输出相同的结果。
如何保证不会输出相同的结果呢,开始想到的是每找到一个结果存起来后,再其后的查找过程中和已有的结果进行对比,当且仅当当前查找的前两个数与已有的所有结果都不相等时才去查找第三个数。这样肯定是可行的,但实现起来很麻烦,与已有结果比较的过程也很浪费时间。
好在题目本身提供了解题思路:题目要求输出结果数组必须按非降序排列。
那么很容易想到先把数组进行排序。然后发现了本题的思路,即第一个数、第二个数、第三个数对应的三重循环中,每结束当前数的一轮循环时,直接跳到下一个与当前数不相等的数进行下一轮循环,这样便可保证找到的结果不会重复。大家可以自己证明一下。
其次,在三重循环中分别设置 (1)
nums[i] <= 0;
(2)
nums[i] + nums[j] <= 0;(3)
nums[i] + nums[j] + nums[k] >= 0
; 这三个进入循环的条件,可以提前终止对相应数的不必要的搜索。
C语言代码如下:
int cmp(const void *a, const void *b)
{
return(*(int *)a-*(int *)b);
}
int** threeSum(int* nums, int numsSize, int* returnSize) {
/* sort the array */
qsort(nums, numsSize, sizeof(nums[0]), cmp);
int i,j,k;
int **result = (int **) malloc(sizeof(int *) * 1000);
*returnSize = 0;
/* find the 3 proper numbers */
for(i = 0; i < numsSize - 2 && nums[i] <= 0; ){
for(j = i + 1; j < numsSize - 1 && nums[i] + nums[j] <= 0; ){
for(k = numsSize - 1; k > j && nums[i] + nums[j] + nums[k] >= 0; ){
if(nums[i] + nums[j] + nums[k] == 0){
if(!(result[(*returnSize)] = (int *)malloc(sizeof(int) * 3))) return NULL;
result[(*returnSize)][0] = nums[i];
result[(*returnSize)][1] = nums[j];
result[(*returnSize)++][2] = nums[k];
}
k--;
/* looking for the first unlike number */
while(k > j && nums[k] == nums[k + 1])
k--;
}
j++;
/* looking for the first unlike number */
while(j < numsSize - 1 && nums[j] == nums[j - 1])
j++;
}
i++;
/* looking for the first unlike number */
while(i < numsSize - 2 && nums[i] == nums[i - 1])
i++;
}
if(*returnSize == 0)
return NULL;
return result;
}
小结:
1)注意加入有效的循环控制条件(临界值),避免无谓的计算。