LeetCode 40

          这个题目还是nsum类型的,不过比上个题更难。上个题的复杂性不是很高,因为不需要考虑到元素的重复性对结果造成干扰,但这道题的话,还是在“集合”里面找出 nsum = target, 每个元素只能使用一次且最后的结果不能重复。那么对于“集合”里面出现的重复的元素的处理就特别棘手。其实代码和上个题的差不多,其实只多了几行,但是这几行代码我却想了一天,甚至睡觉前还想了一段时间,但是下午在做实验的时候突然大脑一闪,突然想到了思路,我今天刚好想到了二叉树的后续非递归遍历的做法,我在这个题也是借鉴相似的做法。不说别的了,说说思路吧:

      我们知道上个题的代码是每次递归传递进去的index和本次的index相同,但是这个题index传递进去的时候要加1,其实这样还远远达不到要求,想想看,“集合”中的重复元素还是没有排除掉,比如集合是“1, 1, 2, 5, 6, 7 ,10”而 target=10,按上题的做法结果肯定会有重复项,‘1, 2, 5’‘1, 7’,因为集合中有两个‘1’,那么我们该如何解决呢?我也想到了一种办法,可以解决问题,但是时间复杂度不够,主要代码如下:

if (target == 0)
{
	int end = ret.size();
	if (end == 0 || tmp != ret[end - 1])
	{
			ret.push_back(tmp);
	}
	return;
}
这样的做法的结果应该是对的,但是重复的判断还是做了,这样没有从根本上解决问题。
        真正的做法是使用一个prev记录从vector里面删掉的数,若再次出现这个数就说明该数会导致结果的重复出现,所以当遇到这个数的时候我们跳过,这样就解决问题了。代码如下:

class Solution {
public:
	vector<vector<int>> combinationSum2(vector<int>& candidates, int target)
	{
		/*
		这个题和上个题差不多吧
		*/
		vector<vector<int>> ret;
		ret.clear();
		vector<int> tmp;
		tmp.clear();
		sort(candidates.begin(), candidates.end());
		_findAllSolve(candidates, ret, tmp, target, 0);
		return ret;
	}

	void _findAllSolve(vector<int>& candidates, vector<vector<int>>& ret, vector<int>& tmp, int target, int index)
	{
		if (target == 0)
		{
			/*
			int end = ret.size();
			if (end == 0 || tmp != ret[end - 1])
			{
				ret.push_back(tmp);
			}
			*/
			ret.push_back(tmp);
			return;
		}
		else
		{
			int count = 0;
			int prev = 0; //保存tmp.back();可以用它来过滤掉重复元素
			
			for (int i = index; i < candidates.size(); ++i)
			{	
				if (candidates[i] > target)
				{
					return;
				}

				if (candidates[i] != prev)
				{
					tmp.push_back(candidates[i]);
				}
				else
				{
					continue;
				}
				_findAllSolve(candidates, ret, tmp, target - candidates[i], i + 1);
				//保存此次vector尾部元素,若下次再遇到该元素直接跳过,避免重复,去掉重复的结果全靠prev
				prev = tmp.back(); 
				tmp.pop_back();	
			}
		}
	}
};
相应的结果如下:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值