zoukankan      html  css  js  c++  java
  • 【字符串】排列组合

    排列

    1、全排列

    输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc,则输出由字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab和cba。

    我们以三个字符abc为例来分析一下求字符串排列的过程。首先我们固定第一个字符a,求后面两个字符bc的排列。当两个字符bc的排列求好之后,我们把第一个字符a和后面的b交换,得到bac,接着我们固定第一个字符b,求后面两个字符ac的排列。现在是把c放到第一位置的时候了。记住前面我们已经把原先的第一个字符a和后面的b做了交换,为了保证这次c仍然是和原先处在第一位置的a交换,我们在拿c和第一个字符交换之前,先要把b和a交换回来。在交换b和a之后,再拿c和处在第一位置的a进行交换,得到cba。我们再次固定第一个字符c,求后面两个字符b、a的排列。

    void arrange(char *s,char *begin,char *end)
    {
        assert(s!=NULL);
        if(begin==end)
        {
            cout<<s<<endl;
            return;
        }
    
        for(char *p=begin;p<=end;p++)
        {
            swap(*p,*begin);
            arrange(s,begin+1,end);
            swap(*p,*begin);
        }
    }

     

    2、去重全排列

          以上的全排列方案,没有考虑重复元素的情况,例如对于字符串hee,的全排列为:hee/hee/ehe/eeh/eeh/ehe,现在要求不输出重复的排列

    思路:

         查看当前待排列元素,是否之前出现过,如果出现过,则不进行交换

    bool repeat(char *s,char *e)
    {
        bool exist=false;
        while(s!=e)
        {
            if(*s==*e)
            {
                exist=true;
            }
            s++;
        }
        return exist;
    }
    
    void arrange_norepeat(char *s ,char *begin,char *end)
    {
        assert(s!=NULL);
        if(begin==end)
        {
            cout<<s<<endl;
            return;
        }
    
        for(char *p=begin;p<=end;p++)
        {
            if(!repeat(begin,p))
            {
                swap(*p,*begin);
                arrange_norepeat(s,begin+1,end);
                swap(*p,*begin);
            }
        }
    }

     

    3、字典顺序输出全排列

    思路:

        (1)对于数组元素array[1,2...n],找出array[k]<array[k+1]的最大k值,其中0<=k<size-1,如果不存在则已经是排序的最大值

        (2)对于a[k+1,k+2....n]找出一个 l,满足a[l]>a[k],且l是所有大于a[k]的最小值

        (3)交换a[l]和a[k]

        (4)对于a[k+1,k+2...n]的所有元素逆序

        步骤(1):

    clipboard[11]

        步骤(2):

    clipboard[12]

        步骤(3):

    clipboard[13]

        步骤(4):

    clipboard[14]

     

    4、非递归版本全排列

    Johnson  Trotter算法:

    思路:

        (1)初始化一个序列 1,2,3....n 并且方向全部向左,然后输出这个序列

        (2)找到最大的 “可移动”元素 K,K和它所指方向的邻居交换,若不存在“可移动数”则退出

        (3)所有比K大的数方向全部逆序,然后输出序列

        (4)跳转到(2)

    注:

        “可移动”数——一个数它的箭头所指的邻居比它小,称其为“可移动”数

    clipboard[19]

     

    组合

        思路:

              0-1背包问题,可以将当前元素放入,也可以不放当前元素

    void combination(const char *s,vector<char>& result)
    {
        if(s==NULL)
            return;
        if(*s==0)
        {
            for(int i=0;i<result.size();i++)
            {
                cout<<result[i];
            }
            cout<<endl;
            return;
        }
    
          //放入当前元素
        result.push_back(*s);
        combination(s+1,result);
        result.pop_back();
        
        //不放入当前元素
        combination(s+1,result);
    }
  • 相关阅读:
    switch 语句注意事项
    line-height 和 font-size的关系
    HTTP 缓存
    hashchange事件的认识
    面向对象的写法,见到就添,持续更新。。。
    chrome浏览器开发者工具之同步修改至本地
    history对象的一些知识点
    你不知道的函数节流,提高你的JS性能!
    玩媒体查询,就是这么简单粗暴!
    css中clip-path属性的运用
  • 原文地址:https://www.cnblogs.com/luosongchao/p/3683682.html
Copyright © 2011-2022 走看看