Combination Sum

题目:

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

The same repeated number may be chosen from C unlimited number of times.

Note:

  • All numbers (including target) will be positive integers.
  • Elements in a combination (a1a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
  • The solution set must not contain duplicate combinations.

For example, given candidate set 2,3,6,7 and target 7
A solution set is: 
[7] 
[2, 2, 3] 

题目大意:题目给定一组数(无序)以及一个数字X,要求输出由该组数组合成X的所有组合,且按照升序排列,允许重复使用数字。

解题思路:之前做了一道N皇后的题目,看到别人采用回溯算法,思路比较清楚,而这道题也恰好可以使用回溯算法。

回溯算法的主要难点在于寻找回溯停止条件,回溯策略以及约束条件。对于这道题目:

约束条件:target 是否等于找到数组合的和。

回溯策略:首先对给定的一组数按升序排序,假设有个棋盘格第一行放置该组数,第二行也放置该组数...这就是要搜索的解空间。以[2,3,4]为例

2 3 4
2 3 4
2 3 4
那么最多有target / combination[0] + 1 行。接下来的策略就是,当target < total时,向下搜索,当target == total时,输出结果,并且向上回溯一行(因为是升序排列),当target > total时,向上回溯一行,需要注意当搜索的列大于combination.size()时,也需要回溯一行。

回溯停止条件:当row == -1 时,算法结束。代码:

class Solution {
public:
	// Judge whether the sum is equal to target
	int isEqual(vector<int> &candidates, vector<int> choosen_num, int row, int target){
		int total = 0;
		for(int i = 0; i <= row; ++i)
			total += candidates[choosen_num[i]];
		if(total == target)
			return 0;
		else if(total < target)
			return 1;
		else 
			return -1;
	}

	vector<vector<int> > combinationSum(vector<int> &candidates, int target) {
		// Sort the candidates, at first.
		sort(candidates.begin(), candidates.end());
		vector<int> choosen_num(target / candidates[0] + 1, 0);
		int row = 0;
		int col_max = candidates.size();
		vector<vector<int> > result;

		while(1){
			// Backtracking 
			// Cols must smaller than candidates's max cols.
			if(choosen_num[row] == col_max){
				row--;
				if(row == -1)
					break;
				choosen_num[row]++;
			}else{
				int flag = isEqual(candidates, choosen_num, row, target);
				if(flag == 1){
					choosen_num[row+1] = choosen_num[row];
					row++;
				}else if( flag == 0){
					vector<int> temp_result;
					for(int i = 0; i <= row; ++i)
						temp_result.push_back(candidates[choosen_num[i]]);
					result.push_back(temp_result);
					row--;
					if(row == -1)
						break;
					choosen_num[row]++;
				} else{
					row--;
					if(row == -1)
						break;
					choosen_num[row]++;
				}
			}
		}
		return result;
	}
};

加强版:

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.
  • Elements in a combination (a1a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
  • 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] 



针对Combination Sum2的版本只需要将每行的首次偏移置为上一行当前值+1既可避免元素重复,为了避免重复解,使用set<vector<int>>即可,最后稍作转换即可,代码如下:

class Solution {
public:
	// Judge whether the sum is equal to target
	int isEqual(vector<int> &candidates, vector<int> choosen_num, int row, int target){
		int total = 0;
		for(int i = 0; i <= row; ++i)
			total += candidates[choosen_num[i]];
		if(total == target)
			return 0;
		else if(total < target)
			return 1;
		else 
			return -1;
	}

	vector<vector<int> > combinationSum(vector<int> &candidates, int target) {
		// Sort the candidates, at first.
		sort(candidates.begin(), candidates.end());
		vector<int> choosen_num(target / candidates[0] + 1, 0);
		int row = 0;
		int col_max = candidates.size();
		set<vector<int> > result;

		while(1){
			// Backtracking 
			// Cols must smaller than candidates's max cols.
			if(choosen_num[row] == col_max){
				row--;
				if(row == -1)
					break;
				choosen_num[row]++;
			}else{
				int flag = isEqual(candidates, choosen_num, row, target);
				if(flag == 1){
					choosen_num[row+1] = choosen_num[row] + 1;
					row++;
				}else if( flag == 0){
					vector<int> temp_result;
					for(int i = 0; i <= row; ++i)
						temp_result.push_back(candidates[choosen_num[i]]);
					result.insert(temp_result);
					row--;
					if(row == -1)
						break;
					choosen_num[row]++;
				} else{
					row--;
					if(row == -1)
						break;
					choosen_num[row]++;
				}
			}
		}
		return vector<vector<int>>(result.begin(), result.end());
	}
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值