题目:
题意:题目意思是从给出的数组中找出三个和为0的元素,返回所有的组合。
分析与思路:对于这种题,没做过这类题的第一反应肯定是暴力求解,三次循环,超出所有的组合然后查重去掉重复的。但是这当然会超时毕竟复杂度达到了O(n3),因此必须另寻出路。为了避免一些重复的遍历,对于找和为定值的两个数时,我们有一种方便的方法:就是先把数组排序(从小到大),然后从数组两端向中间移动,和大于目标则右端指针减一,小于目标左端指针加一,这样可以避免双重循环导致过多重复的遍历,还省去了查重去重的功夫。现在是找出和为0的三个数,那么可以把这道题变一下,在给出数组中取一个数的相反数作为目标,然后找出剩下的数中和为目标的两个数,这样的三个数就是一个组合。再作个优化,我们把排序后的数组从左到右取目标,然后每一轮的初始最左指针就可以指向目标的指针加1,这样就不会导致重复的组合出现了。
代码:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
if (nums.size() == 0 || nums.size() < 3) {//不满足条件的情况
return result;
}
sort(nums.begin(), nums.end());//对数组排序
for (int it = 0; it < nums.size()-2;it++) {//取目标值
if (it > 0 && nums[it] == nums[it - 1]) continue;//对于同目标值的元素可以跳过,因为重复了
int target = -(nums[it]);//取相反数
int l = it + 1, r = nums.size() - 1;//设置左右指针
while (l < r) {
if (nums[l] + nums[r] == target) {
vector<int> re;
re.push_back(nums[it]);
re.push_back(nums[l]);
re.push_back(nums[r]);
result.push_back(re);//把满足要求的组合加到答案中
while (nums[r] == nums[r - 1]) r--;//因为按照左指针不变的情况下,右值相同会得到相同组合
while (nums[l] == nums[l + 1]) l++;
r--;
l++;//已得匹配组合,则两端都需要移到分别跟原来不同值的位置才行
}
else {
if (nums[l] + nums[r] < target) {//小于目标则左指针加1
l++;
}
else {
r--;
}
}
}
}
return result;
}
};