46 全排列(递归)

字符的全排列

题目描述

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

输入描述:

输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。

思路:DFS

代码:

class Solution {
public:
void allpermute(vector<int>&nums,vector<int>temp,vector<vector<int>> &results)
{
    if(temp.size()==nums.size())
    {
        results.push_back(temp);
    }

    for(int i=0;i<nums.size();i++)
    {
        auto iter=find(temp.begin(),temp.end(),nums[i]);
        if(iter!=temp.end())
        {
            continue;
        }
        temp.push_back(nums[i]);
        allpermute(nums,temp,results);
        temp.pop_back();
    }
    return;
}
vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int>>  results ; 
        int len = nums.size();
        vector<int>temp;
        allpermute(nums,temp,results);
        return results;
}
};

字符的组合

题目:输入一个字符串,输出该字符串中字符的所有组合。举个例子,如果输入abc,它的组合有a、b、c、ab、ac、bc、abc。

上面我们详细讨论了如何用递归的思路求字符串的排列。同样,本题也可以用递归的思路来求字符串的组合。

 

 

思路:同样是用递归求解。可以考虑求长度为n的字符串中m个字符的组合,设为C(n,m)。原问题的解即为C(n, 1), C(n, 2),...C(n, n)的总和。对于求C(n, m),从第一个字符开始扫描,每个字符有两种情况,要么被选中,要么不被选中,如果被选中,递归求解C(n-1, m-1)。如果未被选中,递归求解C(n-1, m)。不管哪种方式,n的值都会减少,递归的终止条件n=0或m=0。

//函数功能 : 从一个字符串中选m个元素  
//函数参数 : pStr为字符串, m为选的元素个数, result为选中的  
//返回值 :   无  
void Combination_m(char *pStr, int m, vector<char> &result)  
{  
    if(pStr == NULL || (*pStr == '\0'&& m != 0))  
        return;  
    if(m == 0) //递归终止条件  
    {  
        for(unsigned i = 0; i < result.size(); i++)  
            cout<<result[i];  
        cout<<endl;  
        return;  
    }  
    //选择这个元素  
    result.push_back(*pStr);  
    Combination_m(pStr + 1, m - 1, result);  
    result.pop_back();  
    //不选择这个元素  
    Combination_m(pStr + 1, m, result);  
}  
//函数功能 : 求一个字符串的组合  
//函数参数 : pStr为字符串  
//返回值 :   无  
void Combination(char *pStr)  
{  
    if(pStr == NULL || *pStr == '\0')  
        return;  
    int number = strlen(pStr);  
    for(int i = 1; i <= number; i++)  
    {  
        vector<char> result;  
        Combination_m(pStr, i, result);  
    }  
}  

字符的子集

描述

给定一个含不同整数的集合,返回其所有的子集

子集中的元素排列必须是非降序的,解集必须不包含重复的子集

您在真实的面试中是否遇到过这个题?  是

样例

如果 S = [1,2,3],有如下的解:

 
  1. [

  2. [3],

  3. [1],

  4. [2],

  5. [1,2,3],

  6. [1,3],

  7. [2,3],

  8. [1,2],

  9. []

  10. ]

挑战

你可以同时用递归与非递归的方式解决么?

递归的方法:
不要去想递归是如何一层一层调用的,而是要想如果解决当前问题,找到递归的出口

和字符串的排列一样,将数组分为第一个元素和后面的所有的元素,此时面临取第一个元素,递归剩余的元素或者不取第一个元素(即直接递归剩余元素)

代码如下:
 

class Solution {
public:
    /**
     * @param nums: A set of numbers
     * @return: A list of lists
     */
    vector<vector<int>> subsets(vector<int> &nums) {
        // write your code here
       //这里排序并不必须,只是为了子集中元素以递增排序
        sort(nums.begin(), nums.end());
        vector<vector<int>> subs;
        vector<int> sub;  
        genSubsets(nums, 0, sub, subs);
        return subs; 
    }
    void genSubsets(vector<int>& nums, int start, vector<int>& sub, vector<vector<int>>& subs) {
        //我们发现这里好像并没有递归出口,因为终止条件由下面for循环控制
        subs.push_back(sub);        
        for (int i = start; i < nums.size(); i++) {
            //情况一:子集包含元素nums[i]
            sub.push_back(nums[i]);
            //为何是i+1,因为已经解决了第i个元素,需要递归从第i+1个元素开始求解
            genSubsets(nums, i + 1, sub, subs);
            //情况二:子集不包含nums[i],即略过第i个元素
            //可以想象,不去管上一条递归语句,当下一次循环到i+1时,第i个元素已经略过
            sub.pop_back();
        }
    }
};

 

题目:输入两个整数n和m,从数列1,2,3...n中随意取几个数,使其和等于m,要求列出所有的组合。

 

#include <iostream>  
#include <list>  
using namespace std;  
list<int> list1;  
void find_factor(int sum,int n)  
{  
    //递归出口  
    if(n<=0||sum<=0)  
        return;  
    //输出找到的数  
    if(sum==n)  
    {  
        list1.reverse();  
        for(list<int>::iterator iter=list1.begin();iter!=list1.end();iter++)  
            cout<<*iter<<"+";  
        cout<<n<<endl;  
        list1.reverse();  
    }  
    list1.push_front(n);  
    find_factor(sum-n,n-1);//n放在里面  
    list1.pop_front();  
    find_factor(sum,n-1);//n不放在里面  
}  
  
int main(void)  
{  
    int sum,n;  
    cin>>sum>>n;  
    cout<<"所有可能的序列,如下:"<<endl;  
    find_factor(sum,n);  
    return 0;  
}  


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值