Description
Given an array nums
of n integers, are there elements a, b, c in nums
such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
The solution set must not contain duplicate triplets.
Example:
Given array nums = [-1, 0, 1, 2, -1, -4], A solution set is: [ [-1, 0, 1], [-1, -1, 2] ]
题目传送门
一.题目理解
这是LeetCode的第15题,主要方法是双指针和数组。
题目要求给定含n个元素的数组,找出其中三个相加为0的元素,并把找到的所有情况返回。
二.题目解答
题目好理解,但是有一些细节值得注意。
- 找出所有的情况
- 返回的三元组不能重复
因为,我们需要思考的是:
- 如何对数据去重,防止三元组重复
- 如何快速的搜索到符合条件的三元组
1.set方法
类比第1题,这道题可以认为是随机给定一个值(三元组中第一个数),我们把它当作target值,然后再剩余数组中搜索有没有两数之和等于这个数的相反数。可以看到,这很像第1到题,但与第1题不同的是,答案不是唯一解,而且元素有重复的,因而这里不再适合使用unordered_map。
如何使考虑到的元素不重复,也就是在处理之前或处理之中把重复的数字筛选出去,我们立刻想到STL中set是不重复的,但是如果在搜索前过滤数据到set中,在搜索过程中还要进行某些重复的工作,效率并不高,那是不是能在筛选元素的过程中直接进行处理呢?答案是可以的。
下面是代码:
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { vector<vector<int>> ans; unordered_set<int> s; sort(nums.begin(),nums.end()); for(int i = 0; i < nums.size(); i++) { //去重1 if(i != 0 && nums[i - 1] == nums[i]) continue; s.clear(); for(int j = i + 1; j < nums.size(); j++) { if(s.count(-nums[i] - nums[j])) { ans.push_back({nums[i],nums[j],-nums[i] - nums[j]}); //去重2 while(nums[j + 1] == nums[j] && j + 1 < nums.size()) j++; } s.insert(nums[j]); } } return ans; } };
可以看到,我们去重操作用了两步,第一步是为了防止处理相同的target值,这是因为每次处理不同的target值的时候,符合条件的已经全部找出,下一次如果target值相同,得到的解必然重复);第二步是为了防止出现相同的三元组解,这是因为前两个元素固定了,最后一个元素必然唯一。
2.双指针方法
首先这是个数组,其次要求解的问题与数组元素的值相关,而且对重复值有要求,因为我们可以对其进行预处理以减少操作,这里所做的预处理就是排序。
经过预处理之后,数组变得”良好”,终止条件也比较明确,如果第一个元素就已经是正数,后面的数字一定全部是正数,这样它们的和肯定不是0;其次,再处理元素时,我们可以方便的把要处理的元素和已处理的元素作比较,如果相同,我们也可以跳过,这样对于冗余元素的数组,我们可以大大提高处理速度。
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { vector<vector<int>> ret; vector<int> vec; int target; int front,rear; sort(nums.begin(),nums.end()); for(int i = 0; i < nums.size(); i++) { target = -nums[i]; if(target < 0) break; if(i != 0 && nums[i] == nums[i - 1]) continue; front = i + 1; rear = nums.size() - 1; while(front < rear) { int sum = nums[front] + nums[rear]; if(sum < target) front++; else if(sum > target) rear--; else { vector<int>().swap(vec); vec.push_back(nums[i]); vec.push_back(nums[front]); vec.push_back(nums[rear]); ret.push_back(vec); //去重 while(front < rear && nums[front] == vec[1]) front++; while(front < rear && nums[rear] == vec[2]) rear--; } } } return ret; } };