问题描述:
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], ]
思路:
两种方案:1 递归法;2 构造法。虽然两种方法从时间上分析都是一样的,但是因为递归法会有一些无效的判断和递归调用代价,总的效率是比较低的,但是代码实现简单直观。
1 递归法
void addOne(vector<int> in, vector<int> out, vector<vector<int>> &result, int k){
if (out.size() == k){
result.push_back(out);
return;
}
for (int i = 0; i < in.size(); i++){
vector<int> tempIn = in;
vector<int> tempOut = out;
tempIn.erase(tempIn.begin(), tempIn.begin()+i+1);
tempOut.push_back(in[i]);
addOne(tempIn, tempOut, result, k);
}
}
vector<vector<int>> combine(int n, int k) {
vector<int> in; vector<vector<int>> result;
for (int i = 0; i < n; i++) in.push_back(i + 1);
addOne(in, {}, result, k);
return result;
}
2 构造法
我们构造一个数组ones来表示一种组合模式,ones中的1表示从1-n中提取,0表示不提取。当ones中出现10模式时就将其置换为01,请将该模式前所有的1挪到最左边,当所有的1都在最右边时终止程序。
vector<vector<int>> combine2(int n, int k){
vector<int> ones(n), lib(n); vector<vector<int>> result;
for (int i = 0; i < n; i++){
ones[i] = (i < k) ? 1 : 0; lib[i] = i+1;
}
while (1){
vector<int> solution; bool flag = false;
for (int i = 0; i < n; i++){
if (ones[i]) solution.push_back(lib[i]);
}
result.push_back(solution);
int count = 0;
for (int i = 0; i < n - 1; i++){
if (ones[i] == 1 && ones[i + 1] == 0){
flag = true;
ones[i] = 0; ones[i + 1] = 1;
for (int j = 0; j < i; j++){
ones[j] = count-->0 ? 1 : 0;
}
break;
}
else if (ones[i]) count++;
}
if (!flag) break;
}
return result;
}
贴出运行结果纪念一下: