排列与组合问题

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

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();
    }
}
全部评论

相关推荐

关于“实习生工资多少才算正常”,其实并没有一个放之四海而皆准的标准,但如果结合一线城市的生活成本、工作强度以及实习本身创造的价值来看,我个人认为6000&nbsp;元左右应当是一个基本及格线,也就是每天&nbsp;200&nbsp;多元。如果能达到&nbsp;300、400&nbsp;元一天,甚至更高,那无疑是更理想的状态。首先,从现实成本看,房租、通勤、餐饮几乎都是刚性支出。低于这个水平的实习,往往意味着实习生需要用家庭或存款“倒贴”工作,这在长期来看并不合理。实习本质上是学习,但并不等于“廉价劳动力”,更不应该是经济压力的来源。其次,愿意给实习生更高薪资的公司,通常不会是差公司。这至少说明两点:一是公司资金相对充足,不是靠压缩人力成本勉强维持;二是公司认可实习生的价值,希望你真正参与业务、创造产出,而不是只做边角料工作。很多高薪实习往往伴随着更规范的培养体系、更高的信息密度和更真实的项目经验。当然,高工资并不等于一切,但它往往是一个重要信号。能给到&nbsp;300、400&nbsp;元一天甚至更多的公司,往往对效率、能力和长期发展更有追求,也更可能处在一个有前景的赛道中。总结来说,实习工资不仅是钱的问题,更是公司态度、实力和发展前景的体现。在条件允许的情况下,争取一份“付得起你时间”的实习,本身就是一种理性选择。
北国牛马:你是不是忘了你一周只能上五天班,月薪6000那你日薪就得300了,日薪200一个月也就4000,也就刚好覆盖生活成本了
实习生工资多少才算正常?
点赞 评论 收藏
分享
评论
2
2
分享

创作者周榜

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