输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串 abc,则按字典序打印出所能排列出来的所有字符串 abc,acb,bac,bca,cab,cba
解题思路
我们假设这么一个场景:
- 固定 A 为字符串开头,要知道以 A 开头的组合有多少,则必须知道 A 之后的字符串(B、C)能构成多少种组合
- 固定 B 为字符串开头,要知道以 B 开头的组合有多少,则必须知道 B 之后的字符串能构成多少种组合,但这时剩下的字符只有 C 了,所以得出一个组合就是 ABC
- 固定 C 为字符串开头,要知道以 C 开头的组合有多少,则必须知道 C 之后的字符串能构成多少种组合,但这时剩下的字符只有 B 了,所以得出一个组合就是 ACB
- 固定 B .....
可以发现这是一个递归的过程,或者说基于回溯法的思想。这个规律可以简单总结成:
- 固定第一个字符,递归取得首位后面的各种字符串组
- 再把第一个字符与后面每一个字符交换,并同样递归获得首位后面的字符串组合
- 递归的出口,就是只剩一个字符的时候,递归的循环过程,就是从每个子串的第二个字符开始依次与第一个字符交换,然后继续处理子串
import java.util.ArrayList;
import java.util.Collections;
public class Solution {
public ArrayList<String> Permutation(String str) {
ArrayList<String> list = new ArrayList<>();
if(str != null && str.length() > 0) {
PermutationHelper(list, str.toCharArray(), 0);
Collections.sort(list);
}
return list;
}
public void PermutationHelper(ArrayList<String> list, char[] characters, int i) {
// 如果只剩一个字符,则比较结果集中是否已存在当前组合,没有就添加
if(i == characters.length - 1) {
String str = new String(characters);
if(!list.contains(str)) {
list.add(str);
}
} else {
// 递归的主体,第一次交换相当于固定字符,之后还要交换回来
for(int j = i; j < characters.length; j++) {
swap(characters, i, j);
PermutationHelper(list, characters, i + 1);
swap(characters, i, j);
}
}
}
public void swap(char[] characters, int i, int j) {
char temp = characters[i];
characters[i] = characters[j];
characters[j] = temp;
}
}