输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
解题思路:经典的动态规划问题,固定第一个字符,然后依次将后面的字符串与前面的交换,那么排列的个数就是除了第一个字符以外,其他字符的排列个数+1。也就是固定一个字符串之后,之后再将问题变小,只需求出后面子串的排列个数就可以得出结果,当然第一时间想到的就是递归的算法了。
递归的出口就是只剩一个字符的时候,递归的循环过程,就是从每个子串的第二个字符开始依次与第一个字符交换,然后继续处理子串。
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public class Solution {
public ArrayList<String> Permutation(String str) {
ArrayList<String> list = new ArrayList<>();
if(str.length() < 1) {
return list;
}
printStr(str.toCharArray(), 0, list);
//按字典序排列
Collections.sort(list);
return list;
}
public void printStr(char[] chars, int begin, ArrayList<String> list) {
int length = chars.length;
if (begin == chars.length - 1) {
list.add(String.valueOf(chars));
} else {
Set<Character> charSet = new HashSet<Character>();
for (int i = begin; i < length; i++) {
if(i != begin && charSet.contains(chars[i])) {
//这个判断过滤的是这种情况:acdvba,当轮到第一个a和最后一个a交换时,由于他们相等,所以交换之后并不能产生新的字符串,所以跳过这个交换。
continue;
}
charSet.add(chars[i]);
swap(chars, begin, i);
printStr(chars, begin + 1, list);
swap(chars, i, begin);
}
}
}
public void swap(char[] chars, int i, int j) {
char aChar = chars[i];
chars[i] = chars[j];
chars[j] = aChar;
}
}