Given an array nums
of n integers, are there elements a, b, c in nums
such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
The solution set must not contain duplicate triplets.
Example:
Given array nums = [-1, 0, 1, 2, -1, -4], A solution set is: [ [-1, 0, 1], [-1, -1, 2] ]
Solution:
-
如何找?
最简单的方法是暴力求解,三层for循环判断nums[i]+nums[j]+nums[k]=0,时间复杂度为O(n^3),由于时间复杂度太高,下面进行优化。 -
如何优化?
可通过先对数组进行从小到大排序,可通过快排,排序时间复杂度为O(nlogn),排好序后,固定一个节点,以固定节点的下一个作为首指针,将数组最后一个节点作为尾指针,左右夹逼推进,若三数之和大于0,则说明尾指针太大,需要前移,若三数之和小于0,说明首指针太小,需要后移,近而通过夹逼获得刚好为0的点或不存在刚好为0的点,依次将固定节点从首节点直至倒数第三个节点即可。 -
如何去重?(难点)
思考:出现重复的情况有2种:
(1)考虑数组为[-1 -1 0 1],当固定节点在第一个节点时,[-1 -1 0 1]出现[-1 0 1],符合条件,当固定节点往后移动至下一个-1时,我们知道此时后面一定会出现重复:[-1 -1 0 1](加粗部分),则出现重复条件为当前固定节点等于前一个节点,即去重条件为当固定节点非首节点时,判断固定节点不等于前一个节点。
(2)考虑数组[-1 -1 0 0 1] ,固定节点-1,依次可以得到序列[-1 -1 0 0 1] 和[-1 -1 0 0 1] 此时出现重复,即当首节点往右边移动时,如果满足和为0,如果继续往右移动和当前节点一致时,必然是重复的,即此时去重条件为nums[start]==nums[start+1],start继续后移动,即start++,同理尾节点往前移动和当前节点一致时,去重条件为nums[end]==nums[end-1],尾指针继续前移,end–。
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
//对数组进行排序
ordernums(nums,numsSize);
//初始化
int mallocSize = numsSize*(numsSize);
int** returnArray = (int **)malloc(sizeof(int*)*mallocSize);
*returnColumnSizes = (int *)malloc(sizeof(int*)*mallocSize);
*returnSize = 0;
//fix为固定点,依次往后移动至倒数第三个节点
int sum,start,end;
for (int fix = 0; fix<numsSize-2; fix++) {
//去重(上文重复条件1)
if (fix>0 && nums[fix] == nums[fix-1]) {
continue;
}
start = fix + 1;
end = numsSize - 1;
while (start < end) {
sum = nums[start] + nums[end] + nums[fix];
if (sum==0) {
returnArray[*returnSize] = (int*)malloc(sizeof(int) * 3); // 每次找到一组,二级指针就分配三个空间
(*returnColumnSizes)[*returnSize] = 3; // 记录列数
returnArray[*returnSize][0] = nums[fix];
returnArray[*returnSize][1] = nums[start];
returnArray[*returnSize][2] = nums[end];
(*returnSize)++;
start++;
end--;
//去重(上文重复条件2)
while(start < end && nums[start] == nums[start-1]){
start++;
}
while (start < end && nums[end] == nums[end+1]) {
end--;
}
}else if(sum < 0 ) {
start++;
}else{
end--;
}
}
}
return returnArray;
}
//此时采用冒泡排序
void ordernums(int* num,int size){
for (int j = 0; j<size; j++) {
for (int i = 0; i<size-j-1; i++) {
if (num[i+1]<num[i]) {
int temp = num[i];
num[i] = num[i+1];
num[i+1] = temp;
}
}
}
}