题目描述
输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc,则输出由字符a、b、c 所能排列出来的所有字符串abc、acb、bac、bca、cab 和 cba。
分析与解法
1.通过递归实现,定a求bc的排列以此类推,注意每次交换完成后要回复到原来的顺序,避免遗漏。若字符串中有相同字母,则要进行去重,去重的关键在于与它后面步重复的元素交换,判断交换的两元素是否相等,相等则不交换。if (isUnique(s, start, i)) {swap(s, start, i);//把当前第1个数与后面所有数交换位置,注意所以i是从start开始dfs(s, start + 1, end);swap(s, start, i);//避免遗漏,恢复,保证递归前顺序一致,用于下一次交换}
//字符串的全排列通过递归实现
//在全排列中去掉重复的规则——去重的全排列就是从第一个数字起每个数分别与它后面非重复出现的数字交换
public static void dfs(char[] s, int start, int end) {
//递归结束条件
if (start == end) {
System.out.println(new String(s));//输出一个全排列序列
}
for (int i = start; i <= end; i++) {
if (isUnique(s, start, i)) {
swap(s, start, i);//把当前第1个数与后面所有数交换位置,注意所以i是从start开始
dfs(s, start + 1, end);
swap(s, start, i);//避免遗漏,恢复,保证递归前顺序一致,用于下一次交换
}
}
}
//去重
private static boolean isUnique(char[] s, int begin, int end) {
for (int j = begin; j < end; j++) {
if (s[j] == s[end]) {
return false;
}
}
return true;
}
2. 字典序
字典序解决给定一种排列,求基于字典序的下一种排列。当求全排列时,就要一直吧下一种排列找下去,直至没有。While循环,有下一种排列时为true,输出该排列。循环执行找排列的程序。
//找到下一个数
public static boolean nextPermutation(char[] str) {
int end = str.length - 1;
int swapPoint1 = end, swapPoint2 = end;//swapPoint1从后往前找出那个非递增的数(小于右边那个数)
// the actual swap-point is swapPoint1 - 1
while (swapPoint1 > 0 && str[swapPoint1] <= str[swapPoint1 - 1])
swapPoint1--;
if (swapPoint1 == 0)
return false;
else {//找到递增数
while (swapPoint2 > 0 && str[swapPoint2] <= str[swapPoint1 - 1])
swapPoint2--;//从后往前,找到第一个大于str[swapPoint1 - 1]的数
swap(str, swapPoint1 - 1, swapPoint2);//交换这两个数,并将str[swapPoint1 - 1]后面数反转
reverse(str, swapPoint1, end);
return true;
}
}
//字典序排序6125431的下一个数
//寻找最后一对递增数AB(25)
//之后的最小但大于A的数与A调换(2&3)=>6135421
//之后的数反排(即从小到大排列)=>6131245
public static void CalStringAllPermutation(char[] str) {
Arrays.sort(str);//先将原字符串排序
while (nextPermutation(str)) {
System.out.println(str);
}
}
3.求字符串的所有字符的组合
将字符串中的每个字符看成二叉树的一个节点,根节点为空,每个节点都会有两种选择:要和不要两种选择。定义一个空字符串来保存,要就添加进去,不要就不加。
//输入abc,它的组合有a、b、c、ab、ac、bc、abc
//将字符串中的每个字符看成二叉树的一个节点,根节点为空,每个节点都会有两种选择:要 和 不要 两种选择
public static void charsGroup(int i, String per, char[] str) {
//终止条件
if (i == str.length) {
if (!per.isEmpty()) {
System.out.println(per);
}
} else {
charsGroup(i + 1, per, str);//不要当前字符
charsGroup(i + 1, per + str[i], str);//要当前字符
}
}
public static void printAllGroup(String str) {
if (!str.isEmpty()) {
String per = "";//0-i-1位置上的元素
charsGroup(0, per, str.toCharArray());
} else {
System.out.println("null");
}
}
4.ab输出==>aa,ab,ba,bb
//ab输出==>aa,ab,ba,bb
//利用递归,定义一个变量respos来表示输出的个数,当个数等于字符串长度时输出
private static void perm(char[] buf, char[] chs, int respos) {
if (respos == chs.length) {
System.out.println(new String(buf));
} else {
for (int i = 0; i < chs.length; i++) {
buf[respos] = chs[i];
perm(buf, chs, respos + 1);
}
}
}