排列与组合问题

知识点之排列组合问题
排列组合问题常常使用回溯算法来解决问题,回溯算法的结构框架如下:

void backtracking(参数)
{
    if(终止条件)
    {
        存放结果;
        return;
    }
    for(选择:本层集合中元素(树中节点孩子的数量就是集合的大小))
    {
        处理节点;
        backtracking(路径,选择列表); //递归
        回溯,撤销处理结果;
    }
}

一 排列问题
对于长度为n的某数据进行排列总共有n!种排列方式(当然如果n个数据中存在一样的数据,那么排列的种类数目就会大大减少了)
使用回溯法,对于一个排列,我们可以将其分为第一个数据和后面的数据两个部分,依次将第一个数据和后面的每个数据进行交换(当然也可以使用一个标记数组),确定了第一个数据后,接着去处理后面部分的数据,其方法和前面是一样的,这是一个递归的过程。具体代码如下:

vector<string> Permutation(string str)
{
    vector<string>ret;
    if (str == "")
        return ret;
    sort(str.begin(), str.end()); //对字符串进行升序排序,这样方便之后对重复的排列进行剪枝操作
    cout << str << endl;
    string tmp = "";
    vector<bool> vis(str.size(), false); //设置访问数组,能保证最后结果的字典序
    PermutationCore(ret, tmp, str, vis);
    return ret;
}

void PermutationCore(vector<string>&ret, string &tmp, string &str, vector<bool> &vis)
{
    if (str.size() == tmp.size())
    {

        ret.push_back(tmp); 
        return;
    }
    for (int i = 0; i < str.size(); ++i)
    {
        if (i > 0 && str[i] == str[i - 1] && !vis[i - 1])
            continue;
        if (!vis[i])
        {
            vis[i] = true; //加入处理
            tmp += str[i];
            PermutationCore(ret, tmp, str, vis);
            vis[i] = false; //回溯,撤销处理结果
            tmp.pop_back();
        }
    }
}

二 组合问题
对于长度为n的某数据进行组合总共有2^n-1种组合方式(当然如果n个数据中存在一样的数据,那么组合的种类数目就会大大减少了)
如果输入的数据长度为n,那么这n个字符能构成长度为1,2,…,n的组合,在求长度为m(1<=m<=n)的组合时,可以把n个字符分成第一个字符和后面的字符两个部分,如果组合里面包含第一个字符,则下一步就是在后面的字符中选取m-1个字符;如果组合里面不包含第一个字符,则下一步就是在后面的字符中选取m个字符。这样就形成了递归的函数调用关系f(m,n)=f(m-1,n-1)+f(m,n-1)。代码如下:

vector<vector<int> > Combination(vector<int>number)
{
    vector<vector<int> >ret;
    if (number.empty()) //数据为空就直接返回
        return ret;
    for (int i = 1; i<=number.size(); ++i) //选择长度为i的组合
    {
        vector<int>tmp; //tmp变量存放长度为i的组合结果
        CombinationCore(ret, number, 0, i, tmp); //每次都从第一个字符开始
    }
    return ret;
}
//下面是套用回溯算法的框架的代码
void CombinationCore(vector<vector<int> > &ret,vector<int> &number, int i, int m, vector<int>&tmp)
{
    if(m==0)
    {
        ret.push_back(tmp);
        return;
    }
    for(int j=i;j<number.size();++j)
    {
        tmp.push_back(number[j]);
        CombinationCore(ret,number,j+1,m-1,tmp);
        tmp.pop_back();
    }
}
全部评论

相关推荐

白火同学:1、简历可以浓缩成一页,简历简历先要“简”方便HR快速过滤出有效信息,再要“历”用有效信息突出个人的含金量。 2、教育背景少了入学时间~毕业时间,HR判断不出你是否为应届生。 3、如果你的平台账号效果还不错,可以把账号超链接或者用户名贴到对应位置,一是方便HR知道你是具体做了什么内容的运营,看到账号一目了然,二是口说无凭,账号为证,这更有说服力。
面试被问期望薪资时该如何...
点赞 评论 收藏
分享
头像
01-29 21:31
门头沟学院 Java
哞客37422655...:帮顶,之前看别的帖子有人说tx跟字节的实习生就是转正实习?
点赞 评论 收藏
分享
评论
2
2
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务