题目:77. 组合
思路
回溯法
调试用代码
// 调试用
// 理解不了减枝那个值怎么设置的
class Solution {
private:
int order = 0;
vector<vector<int>> result; // 存放符合条件结果的集合
vector<int> path; // 用来存放符合条件结果
void backtracking(int n, int k, int startIndex) {
if (path.size() == k)
{
result.push_back(path);
return;
}
for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) {
order++;
cout << order << ". ";
cout << "val : " << i;
cout << ", blabla : " << n - (k - path.size()) + 1 << endl;
path.push_back(i); // 处理节点
backtracking(n, k, i + 1); // 递归
path.pop_back(); // 回溯,撤销处理的节点
}
}
public:
vector<vector<int>> combine(int n, int k) {
result.clear(); // 可以不写
path.clear(); // 可以不写
backtracking(n, k, 1);
return result;
}
};
Method 1, 剪枝 from 代码随想录
在for
循环那里,改成i <= n - (k - path.size()) + 1
;
(不好理解,人家作者也说了不好理解)
Method 2, 剪枝,自己想的
// 自己写的剪枝
class Solution {
private:
vector<vector<int>> result; // 存放符合条件结果的集合
vector<int> path; // 用来存放符合条件结果
void backtracking(int n, int k, int startIndex) {
if (path.size() == k)
{
result.push_back(path);
return;
}
for (int i = startIndex; i <= n; i++) {
if((k - path.size()) > (n - i + 1)) // 不够了
{
continue;
}
path.push_back(i); // 处理节点
backtracking(n, k, i + 1); // 递归
path.pop_back(); // 回溯,撤销处理的节点
}
}
public:
vector<vector<int>> combine(int n, int k) {
result.clear(); // 可以不写
path.clear(); // 可以不写
backtracking(n, k, 1);
return result;
}
};
增加了这部分,剩下的这部分数字(包括当前i
)比还需要找的数字数量(总共要找k
个数,已经找到了path.size()
个数字)少:
if((k - path.size()) > (n - i + 1)) // 不够了
{
break;
}
比较符合我的思维,但是从效率的角度来讲可能不是最好的;(不过多一条if
语句也慢不到哪里去)
实际上经过恒等变换,是和Method 1是一样的,不过一开始就看到for
循环里,改变了遍历区间的右端确实可能转不过弯来;