《剑指Offer》字符串的排列
题目描述
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入描述:
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
解题思路:
把一个字符串看成由两部分组成:第一部分是它的第一个字符;第二部分是其后面所有的字符。
(1)第一步把第一个字符和其后面所有的字符交换。(自己和自己交换是一样的,可以不交换,但是后面的交换要包括原字符串)
(2)第二步把第一步求出的所有字符串(包括原字符串)的第二个字符与其后面所有的字符交换。
(3)第三步把第二步求出的所有字符串的第三个字符与其后面所有的字符交换。
(4)同理,…。
(5)一直到达最后一个字符。
简而言之,就是把复杂的问题分解成小的问题。如上,每次固定一个字符,求后面所有字符的排列。第一步我们把字符串划分成第一个字符和其后面所有的字符,然后固定第一个字符,把第一个字符和其后面所有的字符逐一交换。交换完后我们仍把除去第一个字符的后面所有的字符划分成第一个字符和其后面所有的字符…一直这样下去。
例子如下图片所示:图片中的程序执行顺序就是下面代码递归的执行顺序(红色箭头)。
代码如下:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Solution {
public ArrayList<String> Permutation(String str) {
List<String> list = new ArrayList<>();
if (str.length() == 0)
return (ArrayList) list;
Permutation(str.toCharArray(), list, 0);
Collections.sort(list);
return (ArrayList) list;
}
public void Permutation(char[] charArray, List<String> list, int i) {
if (i == charArray.length) {// 递归终止条件,结合图片,看图片中方格内箭头的位置,即i的位置,
// 到达数组末尾时结束递归,即树的叶子结点就是排列的组合
if (!list.contains(new String(charArray)))// 去掉重复的
list.add(new String(charArray));
} else {// 如果未到达数组末尾,则继续递归,把箭头后移,即i+1
for (int j = i; j != charArray.length; j++) {// 把箭头所在的那一位与后面的每一位交换
if (j != i) {// 箭头的那一位,没有必要和自己交换,因为交不交换都是一样的
char t = charArray[j];
charArray[j] = charArray[i];
charArray[i] = t;
}
Permutation(charArray, list, i + 1);// 继续递归,把箭头后移,即i+1
if (j != i) {// 递归完返回上一层,要把数组还原,以继续继续下一位的交换
char t = charArray[j];
charArray[j] = charArray[i];
charArray[i] = t;
}
}
}
}
public static void main(String[] args) {
String str = "abc";
Solution solution = new Solution();
List<String> list = solution.Permutation(str);
for (String s : list) {
System.out.println(s);
}
}
}