C++~LeetCode216-组合总和 III(回溯)

216. 组合总和 III

找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:

  • 只使用数字1到9
  • 每个数字 最多使用一次 

返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。

力扣

示例 1:

输入: k = 3, n = 7
输出: [[1,2,4]]
解释:
1 + 2 + 4 = 7
没有其他符合的组合了。

示例 2:

输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]
解释:
1 + 2 + 6 = 9
1 + 3 + 5 = 9
2 + 3 + 4 = 9
没有其他符合的组合了。

示例 3:

输入: k = 4, n = 1
输出: []
解释: 不存在有效的组合。
在[1,9]范围内使用4个不同的数字,我们可以得到的最小和是1+2+3+4 = 10,因为10 > 1,没有有效的组合。

提示:

  • 2 <= k <= 9
  • 1 <= n <= 60

思路:采用回溯枚举的方式求解。

        本题让我们求组合,组合是无序的,所以1,2    2,1算作是同一个组合,而且题目要求每个数只能使用一次。因此,我们在枚举的时候,如果第一个数是2,那么下一个数我们应该从3开始,而不是1或者2。

首先我们先写好回溯求解的大致模板

void dfs() {
	if (终止条件) {
        //终止访问
	}
	for (本层集合中的每个与元素) {
		//处理元素
		dfs(递归调用对下一层的结点求解)
		//回溯,找另一条路径
	}
}

        接着我们要确定传入的参数,题目给出的n和k以外,我们还需要一个nowSum来表示当前结果集中的和是多少,startNum表示现在从第几个数开始往后访问,因为组合是无序的,这里startNum的目的就是为了防止重复的组合出现。实际上我们还需要两个参数,一个是当前的结果集,一个是总的结果集,这里我定义成了全局变量,如果作为参数传入则需要加上&,切记。

        然后就是确定终止条件,如果当前结果集的数量是k并且和为n,那就将当前结果集加入总的结果集,否则如果出现和>n,结果集size>k,直接返回,相当于顺便做了剪枝

        我们把整个问题的求解看成一颗树,树上的每条路径都是问题的一个可能的解,接着我们就是用for循环遍历当前层的集合元素,也就是当前层的结点,首先从startNum这个数开始,加入结果集,然后递归的去子树中寻找合适的结果集,找完以后返回。去当前层的另一条路径上去找合适的解。

最终代码:

class Solution {
public:
	vector<vector<int>> ans;
	vector<int> path;
	void dfs(int n, int k, int nowSum, int startNum) {
		if (nowSum == n && k == path.size()) {
			ans.push_back(path);
			return;
		} else if (nowSum > n) {
			return;
		} else if (k < path.size()) {
			return;
		}
		for (int i = startNum; i <= 9; i++) {
			path.push_back(i);
			dfs(n, k, nowSum + i, i + 1);
			path.pop_back();
		}
	}
	vector<vector<int>> combinationSum3(int k, int n) {
		dfs(n, k, 0, 1);
		return ans;
	}
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值