40. Combination Sum II

Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.

Each number in C may only be used once in the combination.

Note:

  • All numbers (including target) will be positive integers.
  • The solution set must not contain duplicate combinations.

For example, given candidate set [10, 1, 2, 7, 6, 1, 5] and target 8
A solution set is: 

[
  [1, 7],
  [1, 2, 5],
  [2, 6],
  [1, 1, 6]
]

  这道题是39. Combination Sum的变体,同样是给出一个目标数target(T),在candidates数组(C)中找到和为T的所有可能的组合,主要区别就是candidates数组中的数字不能重复选择。

  在39.Combination Sum的代码中,如果只是单纯地把递归调用的第二个参数right(或left)从i改成i - 1(或i + 1),就会出现重复的组合,例如,若C为(2, 2, 3, 3, 6, 7),则运行结果为[(2, 2, 3), (2, 2, 3), (7)],可见,(2, 2, 3)重复了一次,因为两个(2, 2, 3)中的3是不一样的,一个是C[2],另一个是C[3]。因此,需要做出一定的改动(第5行和第21行),在遍历的过程中,当发现该数字C[i]与前驱(backtrack2)或后继(backtrack1)是一样的,则直接跳过,不进行任何判断,因为以C[i]这个数字开头的遍历早已在其前驱(backtrack2)或后继(backtrack1)进行过一次。

  从本质上讲backtrack1和backtrack2没有什么区别,只是遍历方向不一样,但有趣的是,在39. Combination Sum中用两种函数分别提交得到的Run time相差还是挺大的,分别是29ms和42ms,backtrack2用的时间长些。然而更有趣的是,在本题中,用两种函数得到的Run time分别是22ms和13ms,这次backtrack1用的时间更长些。

  算法的时间复杂度仍然难以计算,但可以知道,在极端情况下——candidates数组中所有数字不重复且它们的和小于target,时间复杂度为O(n!)。

  代码如下:

class Solution {
public:
	void backtrack1(vector<int> com, int right, int target) {
		for (int i = right; i >= 0; i--) {
			if (i < right && candidates[i] == candidates[i + 1]) continue;
			if (candidates[i] > target) continue;
			else if (candidates[i] == target) {
				vector<int> tmp = com;
				tmp.push_back(candidates[i]);
				res.push_back(tmp);
			}
			else {
				vector<int> tmp = com;
				tmp.push_back(candidates[i]);
				backtrack1(tmp, i - 1, target - candidates[i]);
			}
		}
	}
	void backtrack2(vector<int> com, int left, int target) {
		for (int i = left; i < candidates.size(); i++) {
			if (i > left && candidates[i] == candidates[i - 1]) continue;
			if (candidates[i] > target) break;
			else if (candidates[i] == target) {
				vector<int> tmp = com;
				tmp.push_back(candidates[i]);
				res.push_back(tmp);
			}
			else {
				vector<int> tmp = com;
				tmp.push_back(candidates[i]);
				backtrack2(tmp, i + 1, target - candidates[i]);
			}
		}
	}
	vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
		sort(candidates.begin(), candidates.end());
		this->candidates = candidates;
		backtrack1(vector<int>(0), candidates.size() - 1, target);
		//backtrack2(vector<int>(0), 0, target);
		return res;
	}
private:
	vector<int> candidates;
	vector<vector<int>> res;
};



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值