Introduction
Question:15. 三数之和
Analysis
TwoSum 的衍生题目。
与 TwoSum 有几个不一样的点,数组元素有重复了,求的是三元组,而且有多个解,需要返回所有解。target 固定为 0,而不是某个指定值,不需要返回 index了,而是返回值。
- 最简单的方法当然是直接
O(n^3) 遍历啦。
- 先排序,然后 遍历+二分查找,多个解可能会返回同样的解,如果筛掉?
- 用 set 超时。
- 由于遍历时,数组已经有序了,所以可以考虑跳过之前已经查找过的值了。
对比 TwoSum, threeSum 唯一一个放松的条件就是 target 固定为 0 了。
而在一个有序数组中,寻找 a + b == 0 是非常简单的,用两个指针指向数组的开头和末尾:
- 如果 a + b > 0,则移动第一个指针
- 如果 a + b < 0,则移动第二个指针
- 如果 a + b == 0,则找到一个解。
将这个解法扩展到 threeSum,并加上 跳过之前查找过的值 的做法即得到最终解法。
Implement
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| int moveLeft(vector<int> &nums, int left, int right) { left++; while (left < right && nums[left] == nums[left-1]) left++; return left; } int moveRight(vector<int> &nums, int left, int right) { right--; while (left < right && nums[right] == nums[right+1]) right--; return right; } vector<vector<int>> threeSum(vector<int>& nums) { vector<vector<int>> res; sort(nums.begin(), nums.end()); int sum = 0; int v = INT_MIN; for(int i = 0;i < nums.size() && nums[i] <= 0; i++) { if (nums[i] == v) continue; int left = i + 1, right = nums.size() - 1; while (left < right) { sum = nums[i] + nums[left] + nums[right]; if (sum == 0) { res.push_back({nums[i], nums[left], nums[right]}); left = moveLeft(nums, left, right); right = moveRight(nums, left, right); } else if (sum < 0) { left = moveLeft(nums, left, right); } else { right = moveRight(nums, left, right); } } v = nums[i]; } return res; }
|