LeetCode | Combinations(n选k全排列)


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);
}

点赞