- 题目描述:
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2. 解题思路:
我们知道,对于数据的处理来说,有序的数据的处理比无序数据的处理简单很多。所以先对所给的数据进行排序,然后用三指针进行逐一的比对,找出符合要求的三元组。这里需要注意的是,在三元组去重的时候,一定要是在找到一个三元组之后进行去重,这样就不会损失掉[-1,-1 ,2 ]这种类型的三元组了,这种解题思路整体的时间复杂度为O(n^2)
3. 解题代码:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(),nums.end());
vector<vector<int>> res;
//找出特殊情况
if(nums.size() < 3){
return res;
}
//a + b + c = 0;
for(int i = 0 ; i < nums.size()-2 ; i++){
//如果第一个数就大于0,则直接返回
//不能是大于等于 [0,0,0]的情况
if(nums[i] > 0){
return res;
}
//对元素a去重 要注意去重的时候 -1 -1 2 这种情况
//要注意为什么是与nums[i-1] 相比,为什么不能是i+1相比
if(i > 0 && nums[i] == nums[i-1]){
continue;
}
int left = i+1;
int right = nums.size() - 1 ;
while(left < right){
if(nums[i]+nums[left]+nums[right] > 0){
right --;
}
else if(nums[i]+nums[left]+nums[right] < 0){
left ++ ;
}else{
res.push_back(vector <int> {
nums[i], nums[left], nums[right] });
//去重 一定要放在找到一个三元组之后
while( right > left && nums[right] == nums[right-1]){
right--;
}
right --;
while( right > left && nums[left] == nums[left+1]){
left++;
}
left ++;
}
}
}
return res;
}
- tips:
sort(nums.begin(),nums.end());
res.push_back(vector<int> {
nums[i],nums[left],nums[right]});
- 三数最近的和:
此题的解法也是排序之后使用双指针进行夹逼
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(),nums.end());
int i,j,k;
int length = nums.size();
int CloseGap;
int SumCloest;
int sum;
//和求三个数的和的方法类似
for( i = 0 ; i < length-2 ; i++){
//对i进行去重
if(i>1 && nums[i] == nums[i-1]){
continue;
}
j = i+1 ;
k = length-1;
while(j < k){
//对各种求和的情况进行判断
sum = nums[i]+nums[j]+nums[k];
if( sum == target ){
return sum;
}else if(sum > target){
if(abs(sum - target) < CloseGap){
CloseGap = abs(sum - target);
SumCloest = sum;
}
//对k进行去重
while(j < k-1 && nums[k-1] == nums[k]){
k--;
}
k = k-1;
}else{
if(abs(sum - target) < CloseGap){
CloseGap = abs(sum - target);
SumCloest = sum;
}
while(j < k-1 && nums[j+1] == nums[j]){
j++;
}
j = j + 1 ;
}
}
}
return SumCloest;
}
- 四数之和:
求四数之和可以可以采用和求三数之和类似的方法,只是再多加一层循环,但是需要注意一些细节,比如四个数相加之后和溢出的问题,还有第二层去重时候的判断条件 j> i+1 && nums[j] == nums[j-1]中j一定是大于i+1 的 ,比如用例是[ -2,-1,-1,1,1,2,2] 这种类型时,对j去重的时候如果用j>1作为判断条件则会直接排除掉[-1,-1,1,1]这种情况。
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> res;
sort(nums.begin(),nums.end());
int length = nums.size();
int i,j,left,right;
if(length < 4){
return res;
}
for(i = 0 ;i < length-3;i++){
//对nums[i]进行去重
if(i>0 && nums[i] == nums[i-1]){
continue;
}
for(j = i+1;j<length-2;j++){
//对nums[j]进行去重
//考虑 为什么一定是j>i+1 而不能是j>1
if( j> i+1 && nums[j] == nums[j-1]){
continue;
}
left = j+1 ;
right = length-1;
while(left < right){
if(nums[i] + nums[j] == target - nums[left] - nums[right]){
res.push_back({
nums[i],nums[j],nums[left],nums[right]});
//在找到一个四元组之后再进行left 和 right 的去重
while(nums[right] == nums[right-1] && left < right){
right--;
}
while(nums[left] == nums[left+1] && left < right) {
left++;
}
//同时收缩
right--;
left++;
}
else if(nums[i] + nums[j] > target -nums[left] - nums[right]){
right--;
}else{
left++;
}
}
}
}
return res;
}
};