package algorithm;
import java.util.TreeSet;
/*
* 全排列问题
* 去重全排列
* 为方便起见,用123来示例下。123的全排列有123、132、213、231、312、321这六种。首先考虑213和321这二个数是如何得出的。
* 显然这二个都是123中的1与后面两数交换得到的。然后可以将123的第二个数和每三个数交换得到132。同理可以根据213和321来得231和312。
* 因此可以知道——全排列就是从第一个数字起每个数分别与它后面的数字交换。
由于全排列就是从第一个数字起每个数分别与它后面的数字交换。我们先尝试加个这样的判断——如果一个数与后面的数字相同那么这二个数就不交换了。
如122,第一个数与后面交换得212、221。然后122中第二数就不用与第三个数交换了,但对212,它第二个数与第三个数是不相同的,交换之后得到221。
与由122中第一个数与第三个数交换所得的221重复了。所以这个方法不行。
换种思维,对122,第一个数1与第二个数2交换得到212,然后考虑第一个数1与第三个数2交换,此时由于第三个数等于第二个数,所以第一个数不再与第三个数交换。
再考虑212,它的第二个数与第三个数交换可以得到解决221。此时全排列生成完毕。
这样我们也得到了在全排列中去掉重复的规则——去重的全排列就是从第一个数字起每个数分别与它后面非重复出现的数字交换。
*/
public class allPermutation {
public static void main(String[] args) {
// TODO Auto-generated method stub
String str = "1223";
permutate(str);
}
public static void permutate(String str){
if(str.length() == 0 || str == null){
return;
}
TreeSet<String> set = new TreeSet<String>();
char[] c = str.toCharArray();
permutate(c, 0, set);
System.out.println(set.toString());
}
public static void permutate(char[] c, int begin,TreeSet<String> set){
int len = c.length;
if(begin == len){ //后面传入的begin+1会到达len 这个时候表示已经排序完成
set.add(new String(c));
}
for(int target = begin; target<len; target++){ //与后面依次比较 判断能否交换
if(isUnique(c, begin, target)){
swap(c, begin, target);
permutate(c, begin+1,set);;//当前点交换后 就顺位到下一个点继续与其之后的点进行判断交换
swap(c, begin, target);//再次交换回来 保证下次 从第二位遍历时 是在原始序列上进行的
}
}
}
//判断能否交换 ---交换目标之前没有出现相同元素 即可交换
public static boolean isUnique(char[] c, int begin, int target){ //判断能否交换 target之前没有与其相同的就可以交换
for(int i = begin; i<target; i++){
if(c[begin] == c[target]){
return false;
}
}
return true;
}
//交换两个数的方法
public static void swap(char[] c, int i, int j){
char temp = c[i];
c[i] = c[j];
c[j] = temp;
}
}