三数之和(C++) , 三数最近的和,四数之和

  1. 题目描述:
    给你一个包含 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;
    }
  1. tips:
sort(nums.begin(),nums.end());
res.push_back(vector<int> {
    
    nums[i],nums[left],nums[right]});

  1. 三数最近的和:
    此题的解法也是排序之后使用双指针进行夹逼
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;
    }
  1. 四数之和:
    求四数之和可以可以采用和求三数之和类似的方法,只是再多加一层循环,但是需要注意一些细节,比如四个数相加之后和溢出的问题,还有第二层去重时候的判断条件 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;
    }
};

猜你喜欢

转载自blog.csdn.net/qq_43964318/article/details/120177352
今日推荐