这个题目,我没有使用太多技巧,直接解决的。虽然不是很难,但是调试花了不少时间。
提炼重点信息:
1.需要非降序输出,所以处理数据之前,先排序一下,是必要的。
2.数组中三个数相加等于0的三元组,而且满足唯一性:
假设a,b,c是满足相加等于0,而且非降序
那么 a <= 0,a,b固定了,c就固定了。
所以我们确定一个方案:从排序后的数组顺序取值。
假设数组大小是n,a的位置i在0到n-3的范围,b的位置j在a的下一个位置i+1开始到n-2的范围,c的位置k在b的下一个位置j+1到n -1的位置
处理好各种边界,重复计算的地方:
假设a的当前位置的值a[i]等于前一个位置的值a[i-1],那么是可以直接跳过的。为啥?后面的循环是前面循环的子集。同理b也是一样的。
另外left = -(a+b),需要在后续的最大最小值范围之内,即: left < num[j] 肯定在数组后面的值中找不到,数组排序后是非降序的。大于数组最大值,肯定也是找不到的。
在c的位置搜索范围能找到一个c跟left相等就可以停止c的当前搜索了,a,b固定,c一定是唯一的。另外c已经比left大了,也不需要搜索了,后面的值更大。
class Solution { public: vector<vector<int> > threeSum(vector<int> &num) { int n = num.size(); vector<vector<int> > res; sort(num.begin(), num.end()); for(int i=0;i<n-2;i++){ if(num[i] > 0){ break; } if(i > 0 && num[i] == num[i-1]){ continue; } // printf("num[%d] = %d\n",i,num[i]); for(int j=i+1;j<n-1;j++){ if(j > i+1 && num[j] == num[j-1]){ continue; } int left = -(num[i] + num[j]); if(left < num[j]){ break; } if(left > num[n-1]){ continue; } // printf("num[%d] = %d,num[%d] = %d\n",i,num[i],j,num[j]); for(int k=j+1;k<n;k++){ if(num[k] == left){ // printf("num[%d] = %d,num[%d] = %d,num[%d] = %d\n",i,num[i],j,num[j],k,num[k]); res.push_back({num[i],num[j],num[k]}); break; } if(num[k] > left){ break; } } } } return res; } };