Leetcode Sum一类题目

Leetcode里有一类这样的题目,给定一个数组和一个target值,寻找数组中的几个数相加等于target值。

1、two sum,寻找数组中两个数相加等于target值

2、three sum,寻找数组中三个数相加等于target值

3、four sum,,寻找数组中四个数相加等于target值

注:three sum和four sum都是two sum问题的延生

4、寻找任意几个数相加等于target值,注:这里面的数组元素都必须都大于0,否则时间复杂度过大(高手可以计算一下)

接下来我们来一一分析各种情况

1、two sum,寻找数组中两个数相加等于target值。

解题思路:最简单直接的是暴利两层循环方法,其时间复杂度为O(n^2),优化解决two sum问题,把时间复杂度降低到O(nlogn),可以使用map,sort等方法,各位可以自己尝试一下,这里主要使用sort来解决问题:

如果把输入数组排序,那么要找到2个数a , b满足 a + b = target。只需要分别指向数组的开头i和结尾j,观察开头和结尾的和,如果两数之和比target小,则说明需要将开头向中间移动一步,如果两数之和比target大,则说明需要将结尾向中间移动一步,如果两数之和和target一样,则找到了满足条件的两个数,将它存起来,然后继续下一步比较(因为可能有不止一个答案),继续下一步比较的办法是把开头i和结尾j同时向中间移动一步。持续这个过程直到开头i和结尾j相遇。

注意:如果数组为{1,1,2,2},target为3,则如果不采取排重措施将会使结果为{{1,2},{1,2}},显然这不是我们想要的结果我们想要的结果仅仅是{{1,2}},在代码中加上排重代码即可进行排重。

<pre name="code" class="cpp">vector<vector<int> > twoSum(vector<int> &num, int target)
{
	vector<vector<int> > result;
	vector<int> vec;
	sort (num.begin(), num.end()); //排序时间复杂度为O(nlogn)
	int size = num.size();
	int l = 0, r = size - 1;
	int sum;
	while (l < r)//寻找答案时间复杂度为O(n)
	{
	//下面的两个if代码是进行排重处理的,也可以尝试其他排重处理,但个人认为在这里进行排重既方便简洁,还减少了一定的时间开销
		if (l != 0 && num[l] == num[l-1])
		{
			++l;
			continue;
		}
		if (r != size - 1 && num[r] == num[r + 1])
		{
			--r;
			continue;
		}
		sum = num[l] + num[r];
		if (sum == target)
		{
			vec.clear();
			vec.push_back(num[l]);
			vec.push_back(num[r]);
			result.push_back(vec);
		}
		else if (sum < target)
			++l;
		else 
			--r;
	}
	return result;
}


 

2、three sum

如果用暴力搜索,3sum问题的时间复杂度为O(N³)借助解决2sum问题的思路,可以优化解决3sum问题。只需要在2sum的搜索过程外层增加一层循环即可,时间复杂度为O(N²),为什么为O(n^2),three sum的sort排序复杂度没有变还是为O(nlogn),其寻找答案时间复杂度变成了O(n^2),所有最终时间复杂度还是为O(n^2)。


vector<vector<int> > threeSum(vector<int> &num) {
        vector<vector<int> >result;
        vector<int> one;
        sort (num.begin(), num.end());
        for (int i = 0; i < num.size(); ++i)
        {
            if (i != 0 && num[i] == num[i-1])//没有这层去重就会存在超时
                continue;
            int two_sum = 0 - num[i];
            int l = i + 1;
            int r = (int)num.size() - 1;
            while (l < r)
            {
                if (l != i + 1 && num[l] == num[l-1])
                {
                    ++l;
                    continue;
                }
                if (r != num.size() - 1 && num[r] == num[r + 1])
                    {
                        --r;
                        continue;
                    }
                int tmp_sum = num[l] + num[r];
                if (tmp_sum < two_sum)
                    ++l;
                else if (tmp_sum > two_sum)
                    --r;
                else
                {
                    one.clear();
                    one.push_back(-two_sum);
                    one.push_back(num[l]);
                    one.push_back(num[r]);
                    result.push_back(one);
                    ++l;
                    --r;
                }
            }
        }
        return result;
}
3、four sum
类比解决3sum问题过程,也可以优化解决4sum问题。只需要在2sum过程外层增加2层循环,时间复杂度为O(N³)。

 vector<vector<int> > fourSum(vector<int> &num, int target) {
        sort(num.begin(), num.end());
        vector<int> vec;
        vector<vector<int> > result;
        int size = num.size(), sumSub, sum;
        for (int i = 0; i < size; ++i)
        {
            if (i != 0 && num[i] == num[i - 1])
                continue;
            for (int j = i + 1; j < size; ++j)
            {
                if (j != i + 1 && num[j] == num[j-1])
                    continue;
                int l = j + 1;
                int r = size - 1;
                sumSub = num[i] + num[j];
                while (l < r)
                {
                    if (l != j + 1 && num[l] == num[l - 1])
                    {
                        ++l;
                        continue;
                    }
                    if (r != size - 1 &&  num[r] == num[r + 1])
                    {
                        --r;
                        continue;
                    }
                    sum = sumSub + num[r] + num[l];
                    if (sum == target)
                    {
                        vec.clear(); 
                        vec.push_back(num[i]);
                        vec.push_back(num[j]);
                        vec.push_back(num[l]);
                        vec.push_back(num[r]);
                        result.push_back(vec);
                        ++l;
                        --r;
                    }
                    else if (sum > target)
                        --r;
                    else 
                        ++l;
                }
            }
        }
        return result;
    }


4、寻找任意几个数相加等于target值

解题思路:没有限定选取数字的个数,一般使用DFS方法

class Solution {
private:
    vector<vector<int> > ret;
    vector<int> a;
public:
    vector<vector<int> > combinationSum(vector<int> &candidates, int target) {
        sort(candidates.begin(), candidates.end());
        getPath(candidates, 0, candidates.size(), target, 0);
        return ret;
    }
    void getPath(vector<int> &cand, int i, int size, int target, int sum)
    {
        for (int j = i; j < size; ++j)
        {
            if (j != i && cand[j] == cand[j - 1])
                continue;
            sum += cand[j];
            if (sum == target)
            {
                a.push_back(cand[j]);
                ret.push_back(a);
                a.pop_back();
                return;
            }
            else if (sum > target)
            {
                return;
            }
            else 
            {
                a.push_back(cand[j]);
                getPath(cand, j, size, target, sum);//如果递归的是getPath(cand, j + 1, size, target, sum),则数组中的数只能取1次
                a.pop_back();
            }
            sum -= cand[j];
        }
    }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值