leetcode39_组合总和_继续回溯

一.  这题一开始想肯定回溯法, 一开始想了个顺其自然的思路,直接看代码能理解, 结果重复了.

//没有去重,报错
class Solution {
public:
	vector<vector<int>> res;
	void backtrace(int sum, vector<int> tmp, int target, vector<int> candidates) {
		if (sum > target) {
			return;
		}
		if (sum == target) {
			res.push_back(tmp);
			return;
		}
		for (int i = 0; i < candidates.size(); i++) {
			sum += candidates[i];
			tmp.push_back(candidates[i]);
			backtrace(sum, tmp, target, candidates);
			//回溯完成得把之前做的工作都去除.
			sum -= candidates[i];
			tmp.pop_back();
		}
	}
	vector<vector<int>>combinationSum(vector<int>& candidates, int target) {
		vector<int> tmp;
		int sum = 0;
		backtrace(sum, tmp, target, candidates);
		return res;
	}
};

二.   参考大神非常好的讲解, 感觉这篇写的回溯非常不错.

作者:leetcode
链接:https://leetcode-cn.com/circle/article/GV6eQ2/
1.  重复的原因每次backtrace里的for循环都从i=0开始,导致第一次的1,2和第二次的2,1重复(仔细理解一下,大概这个意思).

2. 解决办法大神的意思是设置一个start变量, i每次从start开始,这样不会出现1,2和2,1 这种情况,而是1,2和2,2这种情况.

//大神解法,用start变量限制只能找当前及其以后的元素
class Solution {
public:
	vector<vector<int>> res;
	void backtrace(int start, vector<int> tmp, int target, vector<int> candidates) {
		//达到target,不是用sum,而是每次减对应值,看是否到0.
		if (target < 0) {
			return;
		}
		if (target == 0) {
			res.push_back(tmp);
			return;
		}
		for (int i = start; i < candidates.size(); i++) {
			tmp.push_back(candidates[i]);
			backtrace(i, tmp, target-candidates[i], candidates);
			//回溯完成得把之前做的工作都去除.
			tmp.pop_back();
		}
	}
	vector<vector<int>>combinationSum(vector<int>& candidates, int target) {
		vector<int> tmp;
		backtrace(0, tmp, target, candidates);
		return res;
	}
};

三.  参考大神的动态规划, 因为大神说"随着我把组合总和的IIIIIIV做完,尤其是到IV的时候,回溯算法就超时了,而IV恰好是用动态规划解决的,于是我就思考:能不能用动态规划求解本题."

作者:chun-meng-da-xiao-yang
链接:https://leetcode-cn.com/problems/combination-sum/solution/chao-qiang-gifzhu-ni-shi-yong-dong-tai-gui-hua-qiu/

1.  总结: 求解一个值,需要求解上一个值,进而需要求解上上个值...,这种方法就是动态规划。重复的值只需要进行一次,而后再使用到这个值时,只需要将他的结果拿来适当增加即可。

//动态规划
// 由@pris_bupt提供
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
	//dict[i]代表和为i的vector是啥. 
	unordered_map<int, set<vector<int>>>dict;
	for (int i = 1; i <= target; i++)
		for (int it : candidates)
			if (i == it) dict[i].insert(vector<int>{it});
			else if (i > it)
				for (auto ivec : dict[i - it]) {
					ivec.push_back(it);
					sort(ivec.begin(), ivec.end());
					if (dict[i].count(ivec) == 0)
						dict[i].insert(ivec);
				}
	vector<vector<int>>ans;
	for (auto it : dict[target]) ans.push_back(it);
	return ans;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值