Given two integers n and k, return all possible combinations of k numbers out of 1 … n.
For example,
If n = 4 and k = 2, a solution is:
[ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]
题目解析:
让输出从1…n之间的k个元素。题目很简单,但是做的时候却把思路想偏了。
错误思路:
1、第i个元素入栈,然后k-1个数进行递归;
2、第i个元素出栈,然后k个元素递归。
3、下次循环i+1
方案一:笨方法
这就导致了很多重复数据,又是加标志位又是想其他办法,最后都没很好的解决。其实错误代码出现在了第2步。我们让i出栈以后,就直接进行i+1的循环就行了。—->也就是栈中第i个数据已经变成了a[i+1],肯定不会重复数据。
而上面的错误思路,这层循环和下层循环,都算了i+1次的递归,肯定造成很多重复数据。
代码:
#include <stdio.h>
#include <stdlib.h>
typedef struct{
int *a;
int len;
}Stack;
void Combine(int n,int k);
void PrintCombine(int begin,int n,int k,Stack *S);
int main()
{
int n,k;
while(scanf("%d %d",&n,&k)){
Combine(n,k);
}
return 0;
}
void Combine(int n,int k)
{
Stack S;
S.a = (int *)malloc(k*sizeof(int));
S.len = 0;
PrintCombine(1,n,k,&S);
}
void PrintCombine(int begin,int n,int k,Stack *S)
{
if(k<=0){ //当个数已经满足要求了就直接退出
for(int i = 0;i < S->len;i++)
printf("%d ",S->a[i]);
printf("\n");
return ;
}
if(begin > n){
return ;
}
for(int i = begin;i <= n;i++){
S->a[S->len++] = i; //当前元素选择后递归,
PrintCombine(i+1,n,k-1,S);
S->len--; //这一句就代表退出了i值,要加入i+1
}
}
C++代码
class Solution {
private:
void search(vector<vector<int> > &ans, vector<int> & temp, int n, int last, int step, int k) {
if (step == k) {
ans.push_back(temp);
return;
}
for (int i = last + 1; i <= n; i++) {
temp.push_back(i);
search(ans, temp, n, i, step + 1, k);
temp.pop_back();
}
}
public:
vector<vector<int> > combine(int n, int k) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
vector<vector<int> > ans;
vector<int> temp;
search(ans, temp, n, 0, 0, k);
return ans;
}
};
方案二:无for循环递归
因为递归函数中已经有标记为begin,隐含着要放入数组的信息,所以不用加for循环,直接深入嵌套即可。
void PrintCombine(int begin,int n,int k,Stack *S)
{
if(k<=0){ //当个数已经满足要求了就直接退出
for(int i = 0;i < S->len;i++)
printf("%d ",S->a[i]);
printf("\n");
return ;
}
if(begin > n){
return ;
}
S->a[S->len++] = begin; //当前元素选择后递归,
PrintCombine(begin+1,n,k-1,S);
S->len--; //这一句就代表退出了i值,要加入i+1
PrintCombine(begin+1,n,k,S);
}