给你一个整数数组 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] 。
注意,输出的顺序和三元组的顺序并不重要。
思路一:
排序后使用双指针,不断查找三元组,最后去除重复的三元组,验证得此方法可行
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 (nums == NULL || numsSize < 3) {
return NULL;
}
qsort(nums, numsSize, sizeof(int), cmp);
int** res = (int**)malloc(numsSize * numsSize * sizeof(int*));
*returnColumnSizes = (int*)malloc(numsSize * numsSize *sizeof(int));
for (int i = 0; i < numsSize; i++) {
if (nums[i] > 0) {
break;
}
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int left = i + 1, right = numsSize - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == 0) {
res[*returnSize] = (int*)malloc(sizeof(int) * 3);
res[*returnSize][0] = nums[i];
res[*returnSize][1] = nums[left];
res[*returnSize][2] = nums[right];
(*returnColumnSizes)[*returnSize] = 3;
(*returnSize)++;
while (left < right && nums[left] == nums[++left]);
while (left < right && nums[right] == nums[--right]);
} else if (sum < 0) {
left++;
} else {
right--;
}
}
}
return res;
}
时间复杂度为O(n^2),空间复杂度为O(n)
本题一开始想到用循环来查找,但是循环所要的时间复杂度过高,于是采用先快速排序之后双指针的方法进行答题,时间复杂度减少到O(n^2)。在实际编写代码的过程中,还需考虑若三元组重复的则需去除重复项的问题,采用while (left < right && nums[left] == nums[++left]);代码跳过重复项进行判断,最后成功输出三元组。优化时发现只要排序后最左边的数大于0则不会找到三元组,于是编写了一个判断,如果nums[i]>0则退出循环
问题:空间复杂度可以再降低一些
收获:对此类数字之和问题有了更深的理解,凡是此类问题都可用排序加双指针的方法进行尝试,同时哈希表的方法也可以进行运用
思路二:
哈希表