乘法原理:做一件事,完成它需要分成n个步骤,做第一 步有m1种不同的方法,做第二步有m2不同的方法,……,做第n步有mn不同的
方法,那么完成这件事共有 N=m1m2m3…mn 种不同的方法。这是概率学中的理解
排列:一般地,从n个不同元素中取出m(m≤n)个元素,按照一定的顺序排成一列,叫做从n个元素中取出m个元素的一个排列。
全排列:n个不同元素全部取出的一个排列,叫做n个不同元素的一个全排列。这是组合数学中的理解。
无论何种理解:用代数都可以表示成几个数的连乘,为了研究方便,我们假定我们要用程序解决5以内的阶乘(五个元素以内的全排列)。求阶乘很简单,但是如果我们要求将每一种不同的排列展示,又该如何去解决呐?
例如对“abcd” ,用程序求全排列数,并展示每一个要素。
对于这个问题:我们先进行简单的分析:
若求全排数,我们可以运用上篇日志的方法进行求解:
sum(int n){
if(n==0) //数学中有0的阶乘为1
return 1;
else
return n*sum(n-1);
}
分析第二个问题,既然是全排列,对于abcd这四个字母,我们只要让每一个字母当一次排头,即是4;在加上三个字母的全排列,以此类推,到剩下一个字母的时候,那么它就一种排列,即是它自己
同样的我们用递归的思想去完成这个程序的编写,因为到剩下一个字母时,即是我们所谓递归中的终止条件。
首先写一个方法getString() ,获取我们要排列的字符串
public static String getString() throws IOException{
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String str = br.readLine();
return str;
}
或者
public static String getString() {
Scanner scan = new Scanner(System.in);
String str = scan.nextLine();
return str;
}
至于两个方法的区别,后期文章中会阐述。
我们有一个doAnagram()去完成我们的递归
public static void doAnagram(int newSize){//参数为字符串的长度
if(newSize == 1)
return; //若为一个字母时,方法返回
for(int j=0 ; j<newSize ;j++){
doAnagram(newSize-1);//递归,调用自身方法
if(newSize==2)//用来去掉重复元素的条件
displayWord();//展示元素的方法
rotate(newSize);//元素排列的具体方法
}
}
以下为rotate方法
public static void rotate(int newSize){
int j;
int position = size-newSize;
char temp = arrChar[position];
for(j=position+1; j<size ;j++)
arrChar[j-1] = arrChar[j];
arrChar[j-1] = temp;
}
该方法理解如下所示:
有四个位置 0 1 2 3 和一个 temp位置
他们起初的顺序为 temp 0 1 2 3
a b c d
第一次: temp 0 1 2 3
a b c d
第二次: temp 0 1 2 3
a b c d
最后: temp 0 1 2 3
b c d a
System.out.print(++count+" ");
for(int j=0; j<size; j++)
System.out.print(arrChar[j]);
System.out.print(" ");
System.out.flush();
if(count%6 == 0)
System.out.println(" ");
展示displayWord方法如下
public static void displayWord(){
}
通过以上所有方法,我们即可以得到我们输入的字符串的所有排列。
以下分享网友的写的一个方法
/** * 递归调用方法
* @param parameter 需要排列的参数
* @return 该参数排列所有可能的数组
* 因其结果可能有数字的重复,所以采用Set去重
*/
private static Set<String> action(String parameter){
//如果参数为1,则返回,
//每次递归参数的长度会减少1,这是递归的最后结点
if(parameter.length() == 1){
Set<String> set = new HashSet<String>();
set.add(parameter);
return set;
}
//方法返回数组
Set<String> resultList = new HashSet<String>();
//循环参数,将其分为两段,一段为单个字符,一段为其余的字符串
for(int i=0;i<parameter.length();i++){
//单个字符,如果12345需要排列,首先1不动,2345进行排列
String s = parameter.substring(i,i+1);
//其余的字符串
String rest = parameter.substring(0,i)+parameter.substring(i+1);
//将其余的字符串递归所得到的数组
Set<String> list = action(rest);
//将该单个字符与其余字符串的排列拼起来,既完成了以该字符占第一位,其余字符串进行排列的组合
for(String str : list){
StringBuilder sb = new StringBuilder(s.length()+str.length());
sb.append(s);
sb.append(str);
resultList.add(sb.toString());
}
}
return resultList;
}