力扣四数之和

力扣四数之和

一、题目描述

在这里插入图片描述

二、分析

这道题和:三数之和:三数之和类似,直接放代码:

三、代码

class Solution {
public:
    // 只需要返回三个数的和,根据15的双指针来改
    int threeSumClosest(vector<int>& nums, int target) {
        int n = nums.size();

        if( n < 3 )
            return NULL;

        if( n == 3 )
            return nums[0]+nums[1] + nums[2];

        // 仍然需要重排
        sort( nums.begin(), nums.end() );

        int minMerge = INT_MAX;
        int ans = 0;
        int tmpSum = 0;
        for( int first = 0; first < n; first++ )
        {
            int second = first + 1;
            int third = n - 1;
            while( second < third )
            {
                tmpSum = nums[first] + nums[second] + nums[third];
                
                // 如果当前距离小于目前最小距离,则需要更新
                if( abs(tmpSum - target) < minMerge )
                { 
                        minMerge = abs( tmpSum - target );
                        ans = tmpSum;
                }
                // 然后决定下一步怎么走
                if( tmpSum < target )
                { 
                    // 首先,tmpSum < target说明右侧可能有更好的结果,必须是像右侧走,second++
                    second++;
                }
                else if (tmpSum > target)
                {
                    third--;
                }
                else
                { 
                    // 如果已经相等,那么间隔就是0
                    return ans;
                }
            }
        }
        return ans;
    }
};

四、问题描述

在这里插入图片描述

五、分析

原理和三数之和完全一样

六、代码

class Solution{
	public: 
	vector<vector<int>> fourSum(vector<int>& nums, int target) {
        sort(nums.begin(),nums.end());
        vector<vector<int> > res;
        if(nums.size() < 4)
        return res;
        int a,b,c,d,_size=nums.size();
        for(a = 0;a <= _size - 4;a++)
        {
        	if(a > 0 && nums[a] == nums[a - 1]) 
                continue;      //确保nums[a] 改变了
        	for(b = a + 1;b <= _size - 3;b++)
            {
        		if(b > a + 1 && nums[b] == nums[b - 1])
                    continue;   //确保nums[b] 改变了
        		c = b + 1,d = _size - 1;
        		while(c < d)
                {
        			if(nums[a] + nums[b] + nums[c] + nums[d] < target)
        			    c++;
        			else if(nums[a] + nums[b] + nums[c] + nums[d] > target)
        			    d--;
        			else
                    {
        				res.push_back({nums[a],nums[b],nums[c],nums[d]});
        				while(c < d && nums[c + 1] == nums[c])      //确保nums[c] 改变了
        				    c++;
        				while(c <d && nums[ d - 1] == nums[d])      //确保nums[d] 改变了
        				    d--;
        				c++;
        				d--;
					}
				}
			}
		}
		return res;
    }
};

七、100Sum 问题?

  • 在 LeetCode 上,4Sum 就到头了,但是回想刚才写 3Sum 和 4Sum的过程,实际上是遵循相同的模式的。我相信你只要稍微修改一下 4Sum 的函数就可以复用并解决 5Sum 问题,然后解决 6Sum问题……
  • 那么,如果我让你求 100Sum 问题,怎么办呢?其实我们可以观察上面这些解法,统一出一个 nSum 函数:
/* 注意:调用这个函数之前一定要先给 nums 排序 */
vector<vector<int>> nSumTarget(
    vector<int>& nums, int n, int start, int target) {

    int sz = nums.size();
    vector<vector<int>> res;
    // 至少是 2Sum,且数组大小不应该小于 n
    if (n < 2 || sz < n) 
    	return res;
    	
    // 2Sum 是 base case
    if (n == 2) 
    {
        // 双指针那一套操作
        int lo = start, hi = sz - 1;
        while (lo < hi) 
        {
            int sum = nums[lo] + nums[hi];
            int left = nums[lo], right = nums[hi];
            if (sum < target) 
            {
            	//去掉重复的结果
                while (lo < hi && nums[lo] == left) 
                	lo++;
            } 
            else if (sum > target) 
            {
            	//去掉重复的结果
                while (lo < hi && nums[hi] == right) 
                	hi--;
            } 
            else 
            {
                res.push_back({left, right});
                
                while (lo < hi && nums[lo] == left) 
                	lo++;
                	
                while (lo < hi && nums[hi] == right) 
                	hi--;
            }
        }
    } 
    else 
    {
        // n > 2 时,递归计算 (n-1)Sum 的结果
        for (int i = start; i < sz; i++) 
        {
            vector<vector<int>> 
                sub = nSumTarget(nums, n - 1, i + 1, target - nums[i]);
            for (vector<int>& arr : sub) 
            {
                // (n-1)Sum 加上 nums[i] 就是 nSum
                arr.push_back(nums[i]);
                res.push_back(arr);
            }
            
            while (i < sz - 1 && nums[i] == nums[i + 1]) 
            	i++;
        }
    }
    return res;
}
  • 嗯,看起来很长,实际上就是把之前的题目解法合并起来了,n == 2 时是 twoSum 的双指针解法,n > 2时就是穷举第一个数字,然后递归调用计算 (n-1)Sum,组装答案
  • 需要注意的是,调用这个 nSum 函数之前一定要先给 nums 数组排序,因为 nSum 是一个递归函数,如果在 nSum 函数里调用排序函数,那么每次递归都会进行没有必要的排序,效率会非常低。
  • 比如说现在我们写 LeetCode 上的 4Sum 问题:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
    sort(nums.begin(), nums.end());
    // n 为 4,从 nums[0] 开始计算和为 target 的四元组
    return nSumTarget(nums, 4, 0, target);
}
  • 再比如 LeetCode 的 3Sum 问题,找 target == 0 的三元组:
vector<vector<int>> threeSum(vector<int>& nums) {
    sort(nums.begin(), nums.end());
    // n 为 3,从 nums[0] 开始计算和为 0 的三元组
    return nSumTarget(nums, 3, 0, 0);        
}

那么,如果让你计算 100Sum 问题,直接调用这个函数就完事儿了。

猜你喜欢

转载自blog.csdn.net/wolfGuiDao/article/details/106932520
今日推荐