- 三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:
输入:nums = []
输出:[]
示例 3:
输入:nums = [0]
输出:[]
提示:
0 <= nums.length <= 3000
-105 <= nums[i] <= 105
思考:这个题目是我参考 卡神的做法做出来的,具体网址 https://www.programmercarl.com/ 在这个里面
首先哈希表的方法可以求出来所有的三元组,但是去重的难度非常大
使用双指针的方法,可以将算法的时间复杂度降低一个数量级,对代码的效率提升很高
上代码~
/**
* 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().
*/
// 这个题目使用双指针方法进行求解
// 1、数组进行排序
// 2、对于 a,选择从开头到结尾进行尝试
// 3、对b和c,选择从a的后面一个位置和数组的最后一个位置进行查找
// 4、如果a+b+c>0 说明整体比较大,那么就将c向左移动
// 5、如果a+b+c<0 说明整体比较小,那么将b向右移动
// 6、如果a+b+c=0 说明正好是结果,那么输出结果即可 此时b和c都要进行移动,缩小范围
// 那对结果的去重应该如何进行呢?
void quicksort(int* nums, int left, int right)
{
if (left > right) return;
int mid = partition(nums, left, right);
quicksort(nums, left, mid - 1);
quicksort(nums, mid+1, right);
}
int partition(int* nums, int left, int right)
{
int key = nums[left];
int first = left;
int last = right;
int tmp;
while(first < last) {
//先找右边第一个小于key的值的位置
while(first<last && nums[last] >= key) {
last--;
}
// 再找左边第一个大于key的值的位置
while(first<last && nums[first] <= key) {
first++;
}
// 交换上面两个数的位置
if (first < last) {
tmp = nums[first];
nums[first] = nums[last];
nums[last] = tmp;
}
}
// 交换key的位置
tmp = nums[left];
nums[left] = nums[first];
nums[first] = tmp;
return last;
}
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
quicksort(nums, 0, numsSize - 1);
int** ans = (int**)malloc(sizeof(int*) * 18000);
*returnSize = 0; // 多少个符合条件的三元组
int* col = (int*)malloc(sizeof(int) * 18000);
*returnColumnSizes = col;
int a, b, c;
for (a = 0; a < numsSize - 2; a++) {
// 对a去重剪枝
if (nums[a] > 0) break;
if(a > 0 && nums[a] == nums[a - 1]) {
continue;
}
b = a + 1;
c = numsSize - 1;
while(b < c) {
if (nums[a] + nums[b] + nums[c] < 0) {
b++;
}else if (nums[a] + nums[b] + nums[c] > 0) {
c--;
} else { // 得到的答案
// 获取答案 当nums[a] + nums[b] + nums[c] = 0
ans[*returnSize] = (int*)malloc(sizeof(int) * 3);
ans[*returnSize][0] = nums[a];
ans[*returnSize][1] = nums[b];
ans[*returnSize][2] = nums[c];
col[*returnSize] = 3;
(*returnSize)++;
// 对b和c的去重
while (b < c && nums[c] == nums[c - 1]) c--;
while(b < c && nums[b] == nums[b + 1]) b++;
b++; // 关键一步,忘了处理了
c--;
}
}
}
return ans;
}
总结:
1、对基础算法的实现不熟悉,一个快速排序写了半个小时,最后还是参考人家的实现写出来的,后面多用多练
2、对算法的每个步骤细节没有写清楚,收集答案那块忘了收缩了,然后搞得b和c没有刷新,同时对去重的考虑也不清楚,大脑是混乱的,所以后面写程序的时候所有的步骤实现都写出来,然后再写代码,这样调试的时候会比较快速