问题描述:
Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.
Example:
Input: n = 4, k = 2 Output: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]
源码:
弱智做法
用一个回溯的思想,为了防止重复,加上一句。这样做可以保证后面的值比前面大,就不会有重复的问题。
int i = tmp.empty()? 1: tmp.back();
class Solution {
public:
vector<vector<int>> combine(int n, int k) {
vector<bool> visit(n+1, 0);
vector<vector<int>> result;
vector<int> tmp;
if(n<=0 || k<=0) return result;
help(n, k, result, visit, tmp);
return result;
}
void help(int n, int k, vector<vector<int>> &result, vector<bool> &visit, vector<int> &tmp){
if(k==0){
result.push_back(tmp);
return;
}
int i = tmp.empty()? 1: tmp.back();
for(; i<n+1; i++){
if(!visit[i]){
tmp.push_back(i);
visit[i] = true;
help(n, k-1, result, visit, tmp);
tmp.pop_back();
visit[i] = false;
}
}
}
};
Discuss区有个大神做了很好的优化:
- 首先就是直接用一个start来记录起始位置,不用判断i的起始位置。
- 当你已经确定了m个元素的时候,后面最少要留k-m个为元素,这样让循环更少了一点。
class Solution {
private:
vector<vector<int>> result;
public:
vector<vector<int>> combine(int n, int k) {
vector<int> tmp;
if(n<=0 || k<=0) return result;
help(n, k, k, 1, tmp);
return result;
}
void help(int n, int k, int left, int start, vector<int> &tmp){
if(k==0){
result.push_back(tmp);
return;
}
for(int i=start; i<=n+1-left; i++){
tmp.push_back(i);
help(n, k-1, left-1, i+1, tmp);
tmp.pop_back();
}
}
};