字符串数组全排列——逐个追加组合算法

我们在笔试面试过程中经常会遇到关于排列与组合的问题,其实这些可以通过递归简单的实现,看下面两个例子:

(1)关于字符串排列的问题

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

可以这样想:固定第一个字符a,求后面两个字符bc的排列。当两个字符bc的排列求好之后,我们把第一个字符a和后面的b交换,得到bac;接着我们固定第一个字符b,求后面两个字符ac的排列。现在是把c放到第一位置的时候了。记住前面我们已经把原先的第一个字符a和后面的b做了交换,为了保证这次c仍然是和原先处在第一位置的a交换,我们在拿c和第一个字符交换之前,先要把b和a交换回来。在交换b和a之后,再拿c和处在第一位置的a进行交换,得到cba。我们再次固定第一个字符c,求后面两个字符b、a的排列。这样写成递归程序如下:

 package com.meession.weekWork;
  import java.util.Scanner;
  public class StringAllConbinations {    
      public static void permutateSequence(char[] strArrs,int i){
          char temp;
          if(strArrs==null||i>strArrs.length||i<0){
              return;
          }
          else if(i==strArrs.length){
             System.out.println(strArrs);
         }
         else{
             for(int j=i;j<strArrs.length;j++){
                 temp = strArrs[j];//
                 strArrs[j] = strArrs[i];
                 strArrs[i] = temp;
                 permutateSequence(strArrs, i+1);
                 temp = strArrs[j];//
                 strArrs[j] = strArrs[i];
                 strArrs[i] = temp;
             }
         }
     }
     public static voi main(String[] args) {
         Scanner in = new Scanner(System.in);
         String str = in.nextLine();
         char strArrs[] = str.toCharArray();
         permutateSequence(strArrs, 0);
     }
 }

(2)关于组合的问题

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

假设我们想在长度为n的字符串中求m个字符的组合。我们先从头扫描字符串的第一个字符。针对第一个字符,我们有两种选择:一是把这个字符放到组合中 去,接下来我们需要在剩下的n-1个字符中选取m-1个字符;二是不把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选择m个字符。这两种 选择都很容易用递归实现。

 1 import java.util.ArrayList;
 2 import java.util.List;
 3 import java.util.Queue;
 4 public class Combination {
 5     public static void combiantion(char chs[]){
 6         if(chs==null||chs.length==0){
 7             return ;
 8         }
 9         List<Character> list=new ArrayList();
10         for(int i=1;i<=chs.length;i++){
11             combine(chs,0,i,list);
12         }
13     }
14     //从字符数组中第begin个字符开始挑选number个字符加入list中
15     public static void combine(char []cs,int begin,int number,List<Character> list){
16         if(number==0){
17             System.out.println(list.toString());
18             return ;
19         }
20         if(begin==cs.length){
21             return;
22         }
23         list.add(cs[begin]);
24         combine(cs,begin+1,number-1,list);
25         list.remove((Character)cs[begin]);
26         combine(cs,begin+1,number,list);
27     }
28     public static void main(String args[]){
29         char chs[]={‘a‘,‘b‘,‘c‘};
30         combiantion(chs);
31     }
32 }  

输入一个字符串,输出该字符串中所有字母的全排列。程序请适当添加注释。
C++函数原型: void Print(const char *str)
输入样例: abc

分析:

n个字符串的全排列就是n!,而由于2^32=4294967296,12!=479001600,11!=39916800,

本文讨论的算法在限制n<12,关于n>=12的后续讨论。

另外这里输入的字符也是不重复的,重复的相对复杂,后续可以讨论。

思想是这样的:比如输入字符串是abc,定义vectorA、vectorB。

先取a放到vectorA中,
然后取b,与进行组合,则有ba,ab,放到vectorB中,同时清空vectorA。
再取c,与vectorB里的ba,ab分别组合。依次得到cba,bca,bac和cab,acb,abc,放到vectorA中。

最后遍历不为空的vector,打印出组合结果。

这个算法就是逐个追加组合算法。

代码实现如下:

[cpp] view plain copy

  1. #define MAXNUM 12
  2. //定义2个放结果的vector,交替使用。
  3. std::vector<char*> g_vecA;
  4. std::vector<char*> g_vecB;
  5. void Print(const char *str)
  6. {
  7. char Temp;
  8. int nLen = strlen(str);
  9. char Temp0[2];
  10. Temp0[0]=str[0];
  11. Temp0[1]=‘\0‘;
  12. g_vecA.push_back(Temp0);//先把第一个字母放到容器里
  13. vector<char*>::iterator itor;
  14. for (int i=1; i<nLen; i++)
  15. {
  16. Temp = str[i];
  17. if (g_vecA.size()==0)
  18. {
  19. //遍历B中的元素
  20. for(itor=g_vecB.begin();itor!=g_vecB.end();itor++)
  21. {
  22. char* p = *itor;
  23. int nSize = strlen(p);
  24. //从0到nSize位置放Temp
  25. for (int j=0; j<nSize+1; j++)
  26. {
  27. char* q = new char[nSize+2];//如果放在循环外面则最后都是一个值
  28. for (int k=0; k<j; k++)
  29. {
  30. q[k]=p[k];
  31. }
  32. q[j]=Temp;
  33. for (int m=j+1; m<nSize+1; m++)
  34. {
  35. q[m]=p[m-1];
  36. }
  37. q[nSize+1]=‘\0‘;
  38. g_vecA.push_back(q);
  39. }
  40. }
  41. for (itor = g_vecB.end()-1; itor>=g_vecB.begin(); itor--)
  42. {
  43. char* p = *itor;
  44. g_vecB.erase(itor);
  45. }
  46. g_vecB.clear();
  47. }
  48. else
  49. {
  50. //遍历A中的元素
  51. for(itor=g_vecA.begin();itor!=g_vecA.end();itor++)
  52. {
  53. char* p = *itor;
  54. int nSize = strlen(p);
  55. //从0到nSize位置放Temp
  56. for (int j=0; j<nSize+1; j++)
  57. {
  58. char* q = new char[nSize+2];
  59. for (int k=0; k<j; k++)
  60. {
  61. q[k]=p[k];
  62. }
  63. q[j]=Temp;
  64. for (int m=j+1; m<nSize+1; m++)
  65. {
  66. q[m]=p[m-1];
  67. }
  68. q[nSize+1]=‘\0‘;
  69. g_vecB.push_back(q);
  70. }
  71. }
  72. for (itor = g_vecA.end()-1; itor>=g_vecA.begin(); itor--)
  73. {
  74. char* p = *itor;
  75. g_vecA.erase(itor);
  76. }
  77. g_vecA.clear();
  78. }
  79. }
  80. int nCount = 0;
  81. //打印所有组合
  82. if (g_vecA.size()==0)
  83. {
  84. for(itor=g_vecB.begin();itor!=g_vecB.end();itor++)
  85. {
  86. nCount ++;
  87. char* p = *itor;
  88. cout << p << ", ";
  89. if (nCount%10 == 0)
  90. {
  91. cout << endl;
  92. }
  93. delete p;
  94. p=NULL;
  95. }
  96. }
  97. else
  98. {
  99. for(itor=g_vecA.begin();itor!=g_vecA.end();itor++)
  100. {
  101. nCount ++;
  102. char* p = *itor;
  103. cout << p << ", ";
  104. if (nCount%10 == 0)
  105. {
  106. cout << endl;
  107. }
  108. delete p;
  109. p=NULL;
  110. }
  111. }
  112. g_vecA.clear();
  113. g_vecB.clear();
  114. cout << endl;
  115. }

[cpp] view plain copy

  1. int main()
  2. {
  3. g_vecA.clear();
  4. g_vecB.clear();
  5. char str[MAXNUM];
  6. char Temp[256];
  7. scanf("%s", Temp);
  8. if (strlen(Temp)>=12)
  9. {
  10. cout<<"字符串长度是1-11。" <<endl;
  11. return 0;
  12. }
  13. else
  14. {
  15. strcpy(str, Temp);
  16. }
  17. Print(str);
  18. return 0;
  19. }

测试结果:

当输入abc时:

cba, bca, bac, cab, acb, abc,

当输入abcd时:

dcba, cdba, cbda, cbad, dbca, bdca, bcda, bcad, dbac, bdac,
badc, bacd, dcab, cdab, cadb, cabd, dacb, adcb, acdb, acbd,
dabc, adbc, abdc, abcd,

时间: 2024-10-22 06:36:48

字符串数组全排列——逐个追加组合算法的相关文章

字符串数组元素排列与组合的Java递归实现

排列与组合的Java递归实现 (参考) 我们在笔试面试过程中经常会遇到关于排列与组合的问题,其实这些可以通过递归简单的实现,看下面两个例子: (1)关于字符串排列的问题 输入一个字符串,打印出该字符串中字符的所有排列.例如输入字符串abc,则输出由字符a.b.c所能排列出来的所有字符串abc.acb.bac.bca.cab和cba. 可以这样想:固定第一个字符a,求后面两个字符bc的排列.当两个字符bc的排列求好之后,我们把第一个字符a和后面的b交换,得到bac,接着我们固定第一个字符b,求后面

php数组全排列,元素所有组合

<?php $source = array('pll','我','爱','你','嘿'); sort($source); //保证初始数组是有序的 $last = count($source) - 1; //$source尾部元素下标 $x = $last; $count = 1; //组合个数统计 echo implode(',', $source), "<br>"; //输出第一种组合 while (true) { $y = $x--; //相邻的两个元素 if

字符串的全排列和全组合

输入:abc 输出:bac,cba,acb,bca,cab,abc 全排列的问题: public ArrayList<String> Permutation(String str) { ArrayList<String> list = new ArrayList<String>(); if(str!=null && str.length()>0){ helper(str.toCharArray(),list,0); Collections.sort

字符串全排列和组合算法

打印字符串的全排列 算法的思路: 把一个字符串分成两部分,第一个字符+后面部分所有的字符.这样就能够递归的求解整个过程了: 1.每个字符都做一次首字符 2.当某个字符作为首字符的时候,求后面所有字符的全排列 而这里的求后面所有字符的全排列可以看成递归的子问题 全排列的递归树: 但是这里还有一个问题,那就是字符串中有重复的字符时,这样的算法会增加最后的结果数目.比如说字符串aab,a+ab的全排列,然后交换还是a+ab的全排列.所以会增加结果的数目.解决方案就是:当遇到重复的字符的时候就跳过去,不

获取所有组合算法、获取全排列算法(java)

转载声明:原文转自:http://www.cnblogs.com/xiezie/p/5574516.html 受到ACM1015的影响,个人感觉,有必要对统计学上的 全组合和全排列 进行一个简单的总结 组合数:从m个不同元素中取出n(n≤m)个元素的所有组合的个数,叫做从m个不同元素中取出n个元素的组合数(Combination). 如1,2,3三个元素的全组合为: 1 2 3 12 13 23 123 以下是java实现的获取全组合及其个数的算法: import java.io.Buffere

js多个(N)个数组的的元素组合排序算法,多维数组的排列组合或多个数组之间的排列组合

现在有一批手机,其中颜色有['白色','黑色','金色','粉红色']:内存大小有['16G','32G','64G','128G'],版本有['移动','联通','电信'],要求写一个算法,实现[['白色','16G','移动'], ['白色','16G','联通'] ...]这样的组合,扩张,如果后面还有参数,比如再加一个['国行','港版','美版'],不改程序一样可以执行! 通过上面规律可以发现这个算法就是:一个数组里面包含若干个数组,进行组合 算法代码写法一: // 执行组合排列的函数

字符串或者数字数组全排列

//字符串全排列package com.demo.acm; public class AllSortChar { public static void allSort(char[] buf,int start,int end){ if(start==end){ for(int i=0;i<=end;i++){ System.out.print(buf[i]); } System.out.println(); }else{ //多个字母全排列 for(int i=start;i<=end;i++

(转)C#全排列组合算法

全排列组合算法方法: public static List<List<T>> FullCombination<T>(List<T> lstSource){ var n = lstSource.Count; var max = 1 << n;//1乘以2的n次方 var lstResult = new List<List<T>>(); for (var i = 0; i < max; i++) { var lstTem

算法笔记_025:字符串的全排列(Java)

目录 1 问题描述 2 解决方案 2.1 递归实现 2.2 字典序排列实现   1 问题描述 输入一个字符串,打印出该字符串的所有排列.例如,输入字符串"abc",则输出有字符'a','b','c'所能排列出来的所有字符串"abc","acb","bac","bca","cab","cba". 2 解决方案 2.1 递归实现 从字符串中选出一个字符作为排列的第一个字符