前言
问题:
如:输入一个字符串"abcd",再输入一个整数: 2 ,则输出从4个字符中取2个的字符的排列。
输入界面:
请输入一个字符串:abcd
请输入一个整数:2
输出界面:
取出2个字符的全部排列是:
ab
ac
ad
ba
bc
bd
ca
cb
cd
da
db
dc
一、排列是什么?
排列,从n个不同元素中取出m(m≤n)个元素,按照一定的顺序排成一列,叫做从n个元素中取出m个元素的一个排列 。特别地,当m=n时,这个排列被称作全排列 。
我们可以看到,排列和组合(详情见上一篇对组合的学习)的区别是排列讲究顺序。
二、两种思路
1.标记访问数组递归
代码如下:
public class StringArrangrment {
public static void Arrangrment(String s,int m,int []visitor,char [] result){
if(m==0){
for(int i=result.length-1;i>=0;i--) //保证结果相对有序,倒着输出
System.out.print(result[i]);
System.out.println();
}
else{
for(int i=0;i<s.length();i++){ //往后寻找
if(visitor[i]==0) {
result[m - 1] = s.charAt(i);
visitor[i] = 1; //标记访问
Arrangrment(s, m - 1, visitor, result); //递归寻找(未访问元素)
visitor[i] = 0; //进行下一趟递归,清除标记
}
}
}
}
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
String s=sc.nextLine();
int m=sc.nextInt();
//int型数组初始元素全部为0(也可以用boolean型)
int [] visitor=new int[s.length()];
char[] result=new char[m];
Arrangrment(s,m,visitor,result);
}
}
2.“交换”递归
代码如下:
public class StringArrangrment {
public static void Arrange(String s,int k,int m){
int j;
StringBuilder sb=new StringBuilder(s);
if(k==m) {
for(int i=0;i<m;i++)
System.out.print(s.charAt(i));
System.out.println();
}
else{
for(j=k;j<sb.length();j++){
char temp;
temp=s.charAt(j);
sb.setCharAt(j,s.charAt(k));
sb.setCharAt(k,temp);
s=sb.toString();
Arrange(s,k+1,m);
temp=s.charAt(j);
sb.setCharAt(j,s.charAt(k));
sb.setCharAt(k,temp);
s=sb.toString();
}
}
}
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
String s=sc.nextLine();
int m=sc.nextInt();
Arrange(s,0,m);
sc.close();
}
}
总结
在写递归程序的时候一定要清楚递归终止的条件,如果能真正一步步进入程序理解递归当然很好,但是往往会会深陷其中,这时我们便要更多的关注递归的第一层。
上述两种思路本质上没有什么不同,只是在细节处的处理不同,我们可以选择我们更能理解的那一种。
测试结果: