N数之和的问题

三数之和

什么是三数之和

三数之和,概括起来说就说从一个数组中找到三个数,使三数之和等于目标值。

思路

处理N数之和的问题时,我们首先肯定是对数组进行排序,那么这个问题就变成了从有序数组中找到三个这样的数字能够加起来成为target值。首先想到的是利用暴力解法,三层for循环简单粗暴的解决问题,但是暴力法的会超出时间限制。因此我们需要换一种思路,用双指针法,可以降低一下时间空间复杂度。

例子

在这里插入图片描述这一题的话,有一个关键性的要求是答案是不重复的,因此我们需要做一个去重的操作,去重的操作也是十分的巧妙,在代码中做了注释。

class Solution {
public:
    vector<vector<int>> twoSum(vector<int>&nums,int left,int right,int target,int value)
    {   vector<vector<int>>answers;
        while(left<right)
        {
          
          if(nums[left]+nums[right]==target)
          {
            vector<int>results;
            results.push_back(value);
            results.push_back(nums[left]);
            results.push_back(nums[right]);
            answers.push_back(results);
            //如果left下一个元素等于当前的left值,那么跳过,去除重复寻值
            while(left<right && nums[left]==nums[left+1])
              left++;
            //如果right上一个元素等于当前的right值,那么跳过,去除重复寻值
            while(left<right && nums[right]==nums[right-1])
              right--;
            left++;
            right--;
            
          }
          else if(nums[right]+nums[left]>target)
            right--;
          else
            left++;
        }
        return answers;
    }
    vector<vector<int>> threeSum(vector<int>& nums) {
      vector<vector<int>>answers;
      int n=nums.size();
      sort(nums.begin(),nums.end());
      //枚举a,枚举a的过程中要跳过重复值
      for(int i=0;i<n;i++)
      {
        //枚举a,枚举a的过程中要跳过重复值
          if(i>0 && nums[i]==nums[i-1])
            continue;
          auto result=twoSum(nums,i+1,n-1,-nums[i],nums[i]);
          answers.insert(answers.end(),result.begin(),result.end());
      }
      
      return answers;
    }
};

四数之和

在这里插入图片描述

思路

三数之和下面有了四数之和,方法一样,只是加了一层for循环。都是排序+双指针的思路。

代码

class Solution {
public:
    vector<vector<int>>twoSum(vector<int>& nums, long target,int left,int right,int i,int j)
    {
      vector<vector<int>>answers;
      while(left<right)
      {
        if((long)nums[left]+(long)nums[right]==target)
        {
          vector<int>result;
          result.push_back(nums[i]);
          result.push_back(nums[j]);
          result.push_back(nums[left]);
          result.push_back(nums[right]);
          answers.push_back(result);
          while(left<right && nums[left]==nums[left+1])
            left++;
          while(left<right && nums[right]==nums[right-1])
            right--;
          left++;
          right--;
        }
        else if(nums[left]+nums[right]>target)
          right--;
        else
          left++;
      }
      return answers;
    }
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
      //nums中的四个不同元素加在一起等于target
      //是否能利用三数之和
      //先用枚举法试试,枚举的过程中出现了溢出
      //既然三数之和用到了二数之和,是否四数也可以
      int n=nums.size();
      sort(nums.begin(),nums.end());
      long long target_num;
      vector<vector<int>>answers;
      //枚举a
      for(int i=0;i<=n-4;i++)
      {
        //避免重复值
        
        if(i>0&&nums[i-1]==nums[i])
          {
            continue;
          }
        //枚举b
        for(int j=i+1;j<=n-3;j++)
        {
            if(j>i+1 && nums[j-1]==nums[j])
              continue;
            //cout<<"i:"<<i<<"  "<<"j:"<<j<<"  ";
            target_num=target-(long)nums[i]-(long)nums[j];
            //cout<<nums[i];
            //cout<<"待寻找的值:"<<target_num<<endl;
            auto result=twoSum(nums,target_num,j+1,n-1,i,j);
            answers.insert(answers.end(),result.begin(),result.end());
        }
      }
      return answers;
    }
};

最接近的三数之和

在这里插入图片描述

思路

这题和上面都不一样,这题如果没有恰好等于target的三数之和的话,可以找一个最接近的,也是用双指针法。

代码

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
      //暴力法会超时
      int n=nums.size();
      sort(nums.begin(),nums.end());
      int best=1e7;
      int res;
      //双指针
      for(int i=0;i<n;i++)
      {
        int left=i+1,right=n-1;
        while(left<right)
        {
          int temp=nums[left]+nums[right]+nums[i];
          int diff=target-temp;
          if(temp==target)
            return temp;
          if(target>temp)
            left++;
          else
            right--;
          if(abs(diff)<best)
          {
            best=abs(diff);
            res=temp;
          }
        }
      }
      return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值