剑指offer 字符串全排列
描述
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,
则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
思路
> 这里参考了 https://www.nowcoder.com/questionTerminal/fe6b651b66ae47d7acce78ffdd9a96c7
- 如果无重复,固定第一个字符,递归取得首位后面的各种字符串组合,递归的出口,就是只剩一个字符的时候,递归的循环过程,就是从每个子串的第二个字符开始依次与第一个字符交换,然后继续处理子串。
- 如果有重复,由于全排列就是从第一个数字起,每个数分别与它后面的数字交换。
我们先尝试加个这样的判断(错误)——如果一个数与后面的数字相同那么这两个数就不交换了。例如abb,第一个数与后面两个数交换得bab,bba。但是abb中第二个数和第三个数相同,就不用交换了。
上面假设不成立的原因:如上,得到bab,bba。对于bab,第二个数和第三个数不同,则需要交换,得到bba,这里的bba和开始第一个数与第三个数交换的结果相同了。
因此,换个思维:对abb,第一个数a与第二个数b交换得到bab,然后考虑第一个数与第三个数交换,此时由于第三个数等于第二个数,所以第一个数就不再用与第三个数交换了。再考虑bab,它的第二个数与第三个数交换可以解决bba。此时全排列生成完毕!
import java.util.*;
public class Solution {
public ArrayList<String> Permutation(String str) {
ArrayList<String> list = new ArrayList<String>();
if(str!=null && str.length()>0){
Permuation(str.toCharArray(),0,list);
Collections.sort(list);
}
return list;
}
private void Permuation(char[] chars,int i,ArrayList<String> list){
if(i==chars.length-1){
list.add(String.valueOf(chars));
}else {
Set<Character> charSet = new HashSet<Character>();
for(int j=i;j<chars.length;++j){
if(j==i || !charSet.contains(chars[j])){
charSet.add(chars[j]);
swap(chars,i,j);
Permuation(chars,i+1,list);
swap(chars,j,i);
}
}
}
}
private void swap(char[] cs,int i,int j){
char temp = cs[i];
cs[i] = cs[j];
cs[j] = temp;
}
}