/**
* 功能:肯定某字符串的全部排列组合。java
*/算法
注意:不考虑重复字符。若考虑重复字符,只需在加入permulations时去掉重复的字符串便可。编程
[java] view plain copyapp
一,问题描述spa
给定一个字符串,求出该字符串的全排列。.net
好比:"abc"的全排列是:abc、acb、bac、bca、cab、cbablog
二,实现思路递归
采用递归的方式求解。每次先选定一个字符,而后进行“若干次”交换,求出在选定这个字符的条件下,全部的全排列,并把字符“复位”再交换回来。至此,一趟全排列完成。第二趟,选定下一个字符,而后进行“若干次”交换,求出在选定这个字符的条件下,全部的全排列,并把字符“复位”再交换回来。.....ip
就相似于:(参考网上的解释以下:)rem
设R={r1,r2,...rn}是要进行排列的n个元素.Ri=R-{ri}.集合X中元素的全排列记为
Perm(X).(ri)Perm(X)表示在全排列Perm(X)的每个排列前加上前缀ri获得的排列
R的全排列可概括定义以下:
当n=1时,Perm(R)=(r),其中r是集合R中惟一的元素;
当r>1时,Perm(R)由(r1)Perm(r1),(r2)Perm(r2).....(rn)Perm(rn)构成.
全排列就是从第一个数字起每一个数分别与它后面的数字交换
去重的全排列就是从第一个数字起每一个数分别与它后面非重复出现的数字交换, 用编程的话描述就是第i个数与第j个数交换时,要求[i,j)中没有与第j个数相等的数。
代码实现以下:使用一个LinkedList<String>保存每一种排列,若是字符串中出现有重复的字符,则此方法会求出 重复的排列数,于是LinkedList<String>会保存重复的排列。
import java.util.Collections; import java.util.LinkedList; public class Permutation { public static void allPermutation(String str){ if(str == null || str.length() == 0) return; //保存全部的全排列 LinkedList<String> listStr = new LinkedList<String>(); allPermutation(str.toCharArray(), listStr, 0); print(listStr);//打印全排列 } private static void allPermutation(char[] c, LinkedList<String> listStr, int start){ if(start == c.length-1) listStr.add(String.valueOf(c)); else{ for(int i = start; i <= c.length-1; i++) { swap(c, i, start);//至关于: 固定第 i 个字符 allPermutation(c, listStr, start+1);//求出这种情形下的全部排列 swap(c, start, i);//复位 } } } private static void swap(char[] c, int i, int j){ char tmp; tmp = c[i]; c[i] = c[j]; c[j] = tmp; } private static void print(LinkedList<String> listStr) { Collections.sort(listStr);//使字符串按照'字典顺序'输出 for (String str : listStr) { System.out.println(str); } System.out.println("size:" + listStr.size()); } //hapjin test public static void main(String[] args) { // allPermutation("hapjin"); allPermutation("abc"); } }
若是要想让重复的排列只保存一次,有两种方式:①改进算法,不生成重复的排列 ②用HashSet来保存排列
那当字符串中出现重复的字符时,如何生成不重复的排列?---去重的全排列就是从第一个数字起每一个数分别与它后面非重复出现的数字交换
代码实现以下:(当有重复字符时,也可生成全部正确的排列(排列不会重复))
public class Permutation { public static void allPermutation(String str){ if(str == null || str.length() == 0) return; //保存全部的全排列 LinkedList<String> listStr = new LinkedList<String>(); allPermutation(str.toCharArray(), listStr, 0); print(listStr);//打印全排列 } private static void allPermutation(char[] c, LinkedList<String> listStr, int start){ if(start == c.length-1) listStr.add(String.valueOf(c));//System.out.println(String.valueOf(c)); else{ for(int i = start; i <= c.length-1; i++) { //只有当没有重叠的字符 才交换 if(!isSwap(c, start, i)) { swap(c, i, start);//至关于: 固定第 i 个字符 allPermutation(c, listStr, start+1);//求出这种情形下的全部排列 swap(c, start, i);//复位 } } } } private static void swap(char[] c, int i, int j){ char tmp; tmp = c[i]; c[i] = c[j]; c[j] = tmp; } private static void print(LinkedList<String> listStr) { Collections.sort(listStr);//使字符串按照'字典顺序'输出 for (String str : listStr) { System.out.println(str); } System.out.println("size:" + listStr.size()); } //[start,end) 中是否有与 c[end] 相同的字符 private static boolean isSwap(char[] c, int start, int end) { for(int i = start; i < end; i++) { if(c[i] == c[end]) return true; } return false; } //hapjin test public static void main(String[] args) { // allPermutation("hapjin"); allPermutation("aba"); } }
上面的实现将全部的排列顺序都保存到LinkedList<String>了,这是要注意的。固然也能够不保存排列的顺序,直接输出(allPermutation方法)。
if(start == c.length-1) listStr.add(String.valueOf(c));//保存排列 //System.out.println(String.valueOf(c));//不保存排列,直接输出