先对整个数组进行排序,然后枚举三元组中的最小的那个数,对于剩下的数,可以用双指针处理,
假设当前枚举到的位置为 k,双指针的初始位置分别为 i = k + 1,j = nums.size() - 1.
如果 nums[k] + nums[i] + nums[j] < 0,就 ++ i。这是显然的,因为 k 位置固定不变,-- j 得到的 nums[j] 数更小,要增大三数之和,只能增大 nums[i],即 ++ i
同理,如果 nums[k] + nums[i] + nums[j] > 0,就 --j。
坑点1:需要注意 nums.size() 返回值类型为 size_type,是 unsigned 的,所以如果出现 nums.size() - x < 0 的情况,没有特殊处理 nums.size() - x 将会是一个极大的值
坑点2:不要枚举三数中第二大的数!(即假设 nums[k] 为中间值,然后双指针满足 i < k && k <j)。这样处理不了去重,(通过hash,set等方式去重除外)。如 [-2, -1, -1, 0, 2],需要枚举的是 index == 2 的那一位 -1,才能将 -1 作为中位数的所有满足条件的三位数找完。而 [-4, 0, 2, 2, 4],需要枚举的是 index == 2 的那一个 2,才能将 2 作为中位数的所有满足条件的三位数找完。即某些时候需要的是第一次出现的位置,某些时候需要的是最后一次出现的位置。。。而枚举最小数,就只需要处理第一次出现的位置即可。
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { if(nums.size() < 3) return {}; sort(nums.begin(), nums.end()); vector<vector<int>> res; for(int k = 0; k < nums.size() - 2; ++ k) { if(k > 0 && nums[k] == nums[k - 1]) continue; int i = k + 1, j = nums.size() - 1; while(i < j) { int tmp = nums[k] + nums[i] + nums[j]; if(tmp == 0) { res.push_back({nums[k], nums[i], nums[j]}); ++ i; -- j; while(i < j && nums[i] == nums[i - 1]) ++ i; while(i < j && nums[j] == nums[j + 1]) -- j; } else { tmp < 0 ? ++ i : -- j; } } } return res; } };