LeetCode 回溯算法 216. 组合总和 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 ~ 9 内选取出 k 个相加和为 n 的数,首先确定回溯算法的递归函数的参数和返回值,在去确认终止条件单层搜索过程

解题过程:

  • 首先肯定需要个集合来存放符合条件的结果和最终返回的结果集

输入: 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

没有其他符合的组合了。

通过示例可以看出最后的结果是个二维数组,那肯定需要一个一维数组存放每一次符合条件的组合,另外一个二维数组存放所有符合条件的结果集

vector<int> path;			// 符合条件的结果 
vector<vector<int>> res;	// 存放结果集
  •  确认递归函数的参数和返回值

一般情况下回溯算法中递归函数是没有返回值,除非遇到了特殊情况。所以本题我们只需要确认函数的参数,nk 肯定是需要的,还需要一个 sum 存放 path 元素里的总和于 n 做对比是否相等,一个 startIndex 来确定下一次循环的起始位置。

vector<int> path;			// 符合条件的结果 
vector<vector<int>> res;	// 存放结果集

void backtracking(int n, int k, int sum, int startIndex){

}
  • 确认终止条件 

当 path 里的元素个数等于 k ,并且 sum (path里元素的总和) 等于 n 时说明符合组合条件,加入最终的结果集 res 里。并且 sum 若大于 n 也没有接下去搜索的必要。

vector<int> path;			// 符合条件的结果 
vector<vector<int>> res;	// 存放结果集

void backtracking(int n, int k, int sum, int startIndex){
	if(sum > n) return;		// 剪枝操作  若sum > n 也没有接下去搜索的必要 
		 
    if(path.size() == k){ 
    	if(sum == n) res.push_back(path);	// 符合条件的结果放入结果集 
		return; 
	}
}
  • 单层搜索过程 

从1 ~ 9 内每次选取一个元素 i 加入path,并且sum += i,然后进入下一次的递归函数当中,注意下一层的 startIndex为 i + 1,然后进行最关键的回溯,sum -= i , path中最后一个元素退出。

vector<int> path;			// 符合条件的结果 
vector<vector<int>> res;	// 存放结果集

void backtracking(int n, int k, int sum, int startIndex){
	if(sum > n) return;		// 剪枝操作  若sum > n 也没有接下去搜索的必要 
		 
    if(path.size() == k){ 
    	if(sum == n) res.push_back(path);	// 符合条件的结果放入结果集 
		return; 
	}

	// i <= 9 - (k - path.size()) + 1 剪枝操作 
	for(int i = startIndex; i <= 9 - (k - path.size()) + 1; i++){
		sum += i;
		path.push_back(i);
		backtracking(n , k, sum, i + 1);	// 注意 startIndex 调整为 i + 1 
		sum -= i;			// 回溯 
		path.pop_back();	// 回溯 
	}
}

 这样回溯算法的递归函数就写完了,最后记住在调用的时候设置sum 和 startIndex 的初始值,完整代码如下:

class Solution {
private:
	vector<int> path;			// 符合条件的结果 
	vector<vector<int>> res;	// 存放结果集	 
    void backtracking(int n, int k, int sum, int startIndex){
		if(sum > n) return;		// 剪枝操作  若sum > n 也没有接下去搜索的必要 
		 
    	if(path.size() == k){ 
    		if(sum == n) res.push_back(path);	// 符合条件的结果放入结果集 
			return; 
		}
		
		// i <= 9 - (k - path.size()) + 1 剪枝操作 
		for(int i = startIndex; i <= 9 - (k - path.size()) + 1; i++){
			sum += i;
			path.push_back(i);
			backtracking(n , k, sum, i + 1);	// 注意 startIndex 调整为 i + 1 
			sum -= i;			// 回溯 
			path.pop_back();	// 回溯 
		}
		
	}
	
public:
    vector<vector<int>> combinationSum3(int k, int n) {
		backtracking(n, k, 0, 1);
		return res;
    }
};

执行结果:

通过

显示详情

添加备注

执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户

内存消耗:6.1 MB, 在所有 C++ 提交中击败了96.41%的用户

通过测试用例:18 / 18

猜你喜欢

转载自blog.csdn.net/qq_43833393/article/details/127823856