zoukankan      html  css  js  c++  java
  • java 全组合 与全排列

    一、全组合

    public static  void Combination( ) {
            /*基本思路:求全组合,则假设原有元素n个,则最终组合结果是2^n个。原因是:
             * 用位操作方法:假设元素原本有:a,b,c三个,则1表示取该元素,0表示不取。故去a则是001,取ab则是011.
             * 所以一共三位,每个位上有两个选择0,1.所以是2^n个结果。
             * 这些结果的位图值都是0,1,2....2^n。所以可以类似全真表一样,从值0到值2^n依次输出结果:即:
             * 000,001,010,011,100,101,110,111 。对应输出组合结果为:
            空,a, b ,ab,c,ac,bc,abc.
            这个输出顺序刚好跟数字0~2^n结果递增顺序一样
            取法的二进制数其实就是从0到2^n-1的十进制数
             * ******************************************************************
             * * 
             * */
            String[] str = {"a" , "b" ,"c"};
            int n = str.length;                                  //元素个数。
            //求出位图全组合的结果个数:2^n
            int nbit = 1<<n;                                     // “<<” 表示 左移:各二进位全部左移若干位,高位丢弃,低位补0。:即求出2^n=2Bit。
            System.out.println("全组合结果个数为:"+nbit);
            
            for(int i=0 ;i<nbit ; i++) {                        //结果有nbit个。输出结果从数字小到大输出:即输出0,1,2,3,....2^n。
                System.out.print("组合数值  "+i + " 对应编码为: ");
                for(int j=0; j<n ; j++) {                        //每个数二进制最多可以左移n次,即遍历完所有可能的变化新二进制数值了
                    int tmp = 1<<j ;        
                    if((tmp & i)!=0) {                            //& 表示与。两个位都为1时,结果才为1
                        System.out.print(str[j]);
                    }
                }
                System.out.println();
            }
        } 

    运行流程:
    举例:3个元素:a,b,c。所以有2^3=8个组合结果:所以i=0,1,2,....7.对应应输出 a,b,ab,c...abc  (注意a表示001,不是100.)
    将i变成2进制: i=1 = 001    i=2 =010 i=3=011
        (1)j=0 (1)j=0 (1)j=0    移1位: 1<<j == 001 1<<j == 001 1<<j == 001    和i=001相与,两个位都为1,返回1 与i无相同位 和i=001相与,两个位都为1,返回1   输出:a 输出a (2) j=1 (2) j=1 (2) j=1 再移一位: 1<<j ==010 1<<j ==010    1<<j ==010 与i=001相与。无相同1 和i相与,两个位都为1,返回1 和i相与,两个位都为1,返回1 输出b 输出b (3) j=2 3) j=2 (3) j=2 移一位 1<<j ==100 1<<j ==100 与i无相同位 与i无相同位 与i无相同位 所以i=001, 只输出a. 所以i=010, 只输出b. 所以011,输出ab

    ************************************* * 可见上面每一个数字i,只会判断判断3次,因为只需要移三次位,二进制就遍历完了
    * *************************************    

    ---------------------------------------------------------------------------------------------------------
    另一个大同小异版本代码:
            public static void combination1() {
                /*全组合:
                 * 思路是利用二进制的特性,每次加1即可遍历所有位的不同情况,很好理解
                代码同上
                    */
                String arr[] = { "a", "b", "c"};
                int all = arr.length;
                int nbit = 1 << all;
                for (int i = 0; i < nbit; i++) {
                    StringBuffer sb = new StringBuffer();
                    for (int j = 0; j < all; j++) {
                        if ((i & (1 << j)) != 0) {
                            sb.append(arr[j]);
                        }
                    }
                    System.out.println(sb);
                }

    二、全排列

         递归:

    * 从集合中依次选出每一个元素,作为排列的第一个元素,然后对剩余的元素进行全排列,如此递归处理,
    * 从而得到所有元素的全排列。以对字符串abc进行全排列为例,我们可以这么做:以abc为例:
    * 固定a,求后面bc的排列:abc,acb,求好后,a和b交换,得到bac
    * 固定b,求后面ac的排列:bac,bca,求好后,c放到第一位置,得到cba
    * 固定c,求后面ba的排列:cba,cab。
    *
    * 即递归树:
         str:   a      b        c
            ab ac    ba bc      ca cb
      result:  abc acb    bac bca        cab cba

    public static void permutation1(String str ,String result ,int len){
            /* 全排列 递归实现 
          递归树:
              str:          a            b                c
                          ab ac         ba   bc         ca   cb
            result:        abc acb        bac    bca      cab   cba
             */
            
              //结果 开始传入""   空字符进入   len   是这个数的长度
              if(result.length()==len){            //表示遍历完了一个全排列结果
               System.out.println(result);
              }
              else{
                  for(int i=0;i<str.length();i++){
                      if(result.indexOf(str.charAt(i))<0){    //返回指定字符在此字符串中第一次出现处的索引。
                          //System.out.println("字母:"+str.charAt(i));
                          permutation1(str, result+str.charAt(i), len);
                      }
                  } 
              }
        }

    public static void main(String args[]) throws Exception { 
             String s = "abc";
             String result = "";
             permutation1(s, result, s.length());
        } 
    
    

      

      递归另一种写法:或者采用July的方法:

     从集合中依次选出每一个元素,作为排列的第一个元素,然后对剩余的元素进行全排列,如此递归处理,
    * 从而得到所有元素的全排列。以对字符串abc进行全排列为例,我们可以这么做:以abc为例:
    * 固定a,求后面bc的排列:abc,acb,求好后,a和b交换,得到bac
    * 固定b,求后面ac的排列:bac,bca,求好后,c放到第一位置,得到cba
    * 固定c,求后面ba的排列:cba,cab。

    public static void permutation(String[] str , int first,int end) {
            //输出str[first..end]的所有排列方式
            if(first == end) {    //输出一个排列方式
                for(int j=0; j<= end ;j++) {
                    System.out.print(str[j]);
                }
                System.out.println();
            }
                
            for(int i = first; i <= end ; i++) {
                swap(str, i, first);
                permutation(str, first+1, end);  //固定好当前一位,继续排列后面的
                swap(str, i, first);
            }    
        }
        
        private static void swap(String[] str, int i, int first) {
             String tmp;
             tmp = str[first];
             str[first] = str[i];
             str[i] = tmp;      
        }
    · 
    public static void main(String args[]) throws Exception { String[] str = {"a","b","c"}; permutation(str, 0, 2);    //输出str[0..2]的所有排列方式
    } }

    参考http://blog.csdn.net/morewindows/article/details/7370155 总结:

    1.全排列就是从第一个数字起每个数分别与它后面的数字交换。

    2.去重的全排列就是从第一个数字起每个数 分别与它后面非重复出现的数字交换。

    3.全排列的非递归就是由后向前找替换数替换点,然后由后向前找第一个比替换数大的数与替换数交换,最后颠倒替换点后的所有数据。

     

  • 相关阅读:
    洛谷 P1260 工程规划(差分约束)
    洛谷 P3660 [USACO17FEB]Why Did the Cow Cross the Road III G(树状数组)
    [模板]单调队列
    [模板]LIS(最长上升子序列)
    洛谷 P2899 [USACO08JAN]手机网络Cell Phone Network(树形动规)
    如何求数字n的因数个数及因数和
    [模板]tarjan缩点+拓扑排序
    itext生成pdf(附带页眉,页脚,页码)
    工作总结03
    工作总结02(海报上传模块)
  • 原文地址:https://www.cnblogs.com/lifegoesonitself/p/3225803.html
Copyright © 2011-2022 走看看