这个题我主要是卡在了两个地方,我首先想到的是先固定两个数字,然后再去遍历最后一个数字寻找符合条件的数组,后来发现这种方法有点复杂,有一种方法比较的巧妙,代码中也是用到了这种思想,其实,我也想到了一点点,就是采用两头夹逼得方式进行遍历,但是想了想这些数又毫无顺序,然后就没有继续思考了,这种方法的巧妙之处就在于它首先将数的大小进行排序然后进行遍历,厉害吧~
主要思路如下:
1、先升序排序,这里可以直接使用vector容器中的sort函数,然后从头开始遍历确定第一个数字,这是第一重循环;
2、在第二重循环中,第二个数和第三个数分别从数组两端往中间夹逼,再次注意,现在这个数组中的数字是升序排列的:
如果三个数相加正好等于零,符合题目要求,输出即可;
如果三个数相加小于零,说明第二个数字小了,将第二个数字右移;
如果三个数相加大于零,说明第三个数字大了,将第三个数字左移。
3、需要注意的是,这里面会有重复的数字,可以通过判断是否有重复的数字来跳过重复元素。网上说还可以用map来实现,我并没有看懂,懂的大神能否实现一下呢~
4、它的时间复杂度是O(n^2)。
class Solution{
public:
vector<vector<int>> threeSum(vector<int>& nums){
vector<vector<int>> ret;
int size = nums.size();
sort(nums.begin(), nums.end());
for(int i = 0; i < size; i++){
//skip same i
while(i > 0 && i < size && nums[i] == nums[i-1])
i++;
int j = i + 1;
int k = size - 1;
while(j < k){
int sum = nums[i] + nums[j] + nums[k];
if(sum == 0){
vector<int> cur(3);
cur[0] = nums[i];
cur[1] = nums[j];
cur[2] = nums[k];
ret.push_back(cur);
j++;
k--;
//skip same j
while(j<k && nums[j] == nums[j-1])
j++;
//skip same k
while(k>j && nums[k] == nums[k+1])
k--;
}
else if(sum < 0){
j++;
//skip same j
while(j < k && nums[j] == nums[j-1])
j++;
}
else{
k--;
//skip same k
while(k > j && nums[k] == nums[k+1])
k--;
}
}
}
return ret;
}
};