题目
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
分析
先确定字符串中第i个位置上的字符,剩余的字符递归进行全排列。例如,确定第一个位置上的字符为a,那么继续求bc的全排列就可以找到所有以a开头的字符串;确定第一个位置上的字符为b,求ac的全排列;确定第一个位置上的字符为c,求ab的全排列。当第一个位置上的字符确定后,找剩余的字符的全排列又可以重新从第二个位置上确定元素,递归进行。
因为每当确定了一个位置上的字符后,剩余字符需要传递下去进行递归操作,这里采用交换的方法来解决。将确定的字符与当前第 i个字符相交换,然后i+1-N-1依然是剩下的字符。 但是要注意,这样做改变了字符数组,必须进行完一次dfs过程后,将数组复原,便于确定i位置其他元素时,不会受到影响。简单来说,就是当找到以a开头的所有字符串后,要将参与递归的字符串恢复到abc的状态,以便a和b进行交换,查找以b开头的全排列。
如何去重(原来字符串中有重复的字符,例如:aabc)?只要每一层确定的字符不一样,那么便不会出现重复元素,换句话说,只要每一次递归枚举确定i元素时,不出现重复的即可,这可用set实现。
代码
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
public class Solution {
public ArrayList<String> Permutation(String str) {
ArrayList<String> list = new ArrayList<String>();
int length = str.length();
if (length == 0){
return list;
}
char[] temp = str.toCharArray();
slove(list,temp,0);
Collections.sort(list);
return list;
}
private void slove(ArrayList<String> list, char[] temp, int i) {
if (i == temp.length){
list.add(new String(temp));
return;
}
HashSet<Character> set = new HashSet<Character>();
for (int j = i; j < temp.length; j++) {
if (!set.contains(temp[j])){
set.add(temp[j]);
//交换
swap(temp,i,j);
slove(list, temp, i + 1);
swap(temp,i,j);
}
}
}
private void swap(char[] temp, int i, int j) {
char c = temp[i];
temp[i] = temp[j];
temp[j] = c;
}
}