第一道题目:字符串的全排列问题
pf:
input:abc
output:
abc
acb
bac
bca
cab
cba
(注意这里暗指输出是有序的。)
解法:
递归过程如下:
具体
package aiqiyi;
import java.util.Scanner;
import java.util.TreeSet;
/**
* Created by lcq on 2016/9/27.
*/
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
TreeSet<String> set = new TreeSet<>();
String input = sc.nextLine();
char[] buf = input.toCharArray();
permutation(buf,0,buf.length-1,set);
for(String str:set){
System.out.println(str);
}
}
}
public static void permutation(char[] buf, int start, int end,TreeSet<String>set) {
if (start == end) {// 当只要求对数组中一个字母进行全排列时,只要就按该数组输出即可
System.out.println(new String(buf)+set.size());
set.add(new String(buf));
} else {// 多个字母全排列
for (int i = start; i <= end; i++) {
char temp = buf[start];// 交换数组第一个元素与后续的元素
buf[start] = buf[i];
buf[i] = temp;
permutation(buf, start + 1, end,set);// 后续元素递归全排列
temp = buf[start];// 将交换后的数组还原
buf[start] = buf[i];
buf[i] = temp;
}
}
}
}
另外这种全排列字符串的方法对于abb形式的字符串会产生重复结果,因此需要去重。
去重的原则:
由于全排列就是从第一个数字起,每个数分别与它后面的数字交换,我们先尝试加个这样的判断——如果一个数与后面的数字相同那么这两个数就不交换 了。例如abb,第一个数与后面两个数交换得bab,bba。然后abb中第二个数和第三个数相同,就不用交换了。但是对bab,第二个数和第三个数不 同,则需要交换,得到bba。由于这里的bba和开始第一个数与第三个数交换的结果相同了,因此这个方法不行。
换种思维,对abb,第一个数a与第二个数b交换得到bab,然后考虑第一个数与第三个数交换,此时由于第三个数等于第二个数,所以第一个数就不再用与第三个数交换了。再考虑bab,它的第二个数与第三个数交换可以解决bba。此时全排列生成完毕!
这样,我们得到在全排列中去掉重复的规则:
去重的全排列就是从第一个数字起,每个数分别与它后面非重复出现的数字交换。
即对于abb,a与第一个数b交换后就不需要与第二个b进行交换了。
public static void permutation(char[] buf, int start, int end) {
if (start == end) {//打印输出
System.out.println(new String(buf));
} else {// 多个字母全排列
for (int i = start; i <= end; i++) {
if(is_swap(start,i,buf)){ //是否有重复,进行交换;
char temp = buf[start];// 交换数组第一个元素与后续的元素
buf[start] = buf[i];
buf[i] = temp;
permutation(buf, start + 1, end,set);// 后续元素递归全排列
temp = buf[start];// 将交换后的数组还原
buf[start] = buf[i];
buf[i] = temp;
}
}
}
}
}
public boolean is_swap(int start,int k,char[] buf){
boolean flag = true;
for(int i = start;i < k;++i){
if(buf[start] == buf[k]){
flag = false;
break;
}
}
return flag;
}