LeetCode_0077题解 回溯应用之组合问题
0077. Combinations
Given two integers n and k, return all possible combinations of k numbers out of the range [1, n].
You may return the answer in any order.
Example 1:
Input: n = 4, k = 2
Output:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
Example 2:
Input: n = 1, k = 1
Output: [[1]]
Constraints:
1 <= n <= 20
1 <= k <= n
//内功修炼之回溯法的核心:
/* (1)所有回溯法的问题都可以抽象为树形结构
* (2)回溯法解决的都是在集合中递归查子集, 集合的大小就构成了树的宽度, \
递归的深度,都构成的树的深度。
* (3)for循环可以理解是横向遍历, 其内部的backtracking(递归)就是纵向遍历
*
* */
//回溯法套路模板:
/*
* (1)回溯函数模板返回值以及参数: 返回值 bk(参数){ }
* 本题: void backTracking(int n, int k, int startIndex){}
* (2)回溯函数终止条件: if(可以终止){存结果 + return}
* 本题: path.size() == k
* (3)回溯搜索的遍历过程: for(树的某一层元素集合){ 处理节点; 递归; 回溯处理结果; }
* 本题: for(int i = startIndex; i <= n; ++i){ //路径+1 }
* (4)剪枝(升华)
* */
//回溯的剪枝
/*
* 一般可以在回溯函数的开头, 也可以放到for 循环里面
* 剪枝思路: 因为"for(树的某一层元素集合)", 思考, 这个集合是不是太大了?
* 剪枝本质: 剪枝就是剪树节点的子孩子
*
*/
代码
class Solution {
public:
vector<vector<int>> combine(int n, int k) {
result.clear();
path.clear();
backTracking(n, k, 1);
/*for_each(vec.begin(), vec.end(), [](auto &elem){
for_each(elem.begin(), elem.end(), [](auto &x){
cout << x << " ";
});
cout << endl;
});*/
return result;
}
void backTracking(int n, int k, int startIndex){
//剪枝思考:
//"startIndex包括进去varr[startIndex], 还有多少元素" vs "path的大小size()还需要多少元素到k"
//传入4 3
//比较:
//比如 4 - 3 + 1 = 2 vs 3 - 0(path.size()) = 能放 ; 3 2
//剪枝方式一(方式一二差不多, 方式二看着整洁点):
/* if(n - startIndex + 1 < k - (int)path.size()){ */
/* return; */
/* } */
if((int)path.size() == k){
result.push_back(path);
return;
}
//剪枝方式二:
for(int i = startIndex; i <= n + 1 - k + (int)path.size(); ++i){
path.push_back(i);
backTracking(n, k, i + 1);
path.pop_back();
}
}
private:
vector< vector<int> > result;//存放符合条件的各个组合结果的集合
vector< int > path;//存放符合条件的单个组合结果
};
//若人静坐一须臾, 胜造恒沙七宝塔

本文详细讲解了如何使用回溯法解决LeetCode第77题——从n个数中选取k个的不同组合,通过模板展示核心思想,并提供了代码实现。通过实例演示,帮助读者理解回溯法在组合问题中的应用。
405

被折叠的 条评论
为什么被折叠?



