面试:字符串的全排列

1.题目

  输入一个字符串,打印出该字符串中字符的全排列。例如输入字符串abc,则打印出[cab, abc, cba, bca, bac, acb]

题目难度适中,可以考察递归、非递归、是否有无重复字符的全排列等。

2.思路

  对于全排列,比如有3个字符abc,共有3!=6种排列.

首先分析出数学递归公式。
假设abcde是一个输入参数,输出的值则是一个全排列集合。可以有:

1 f(abcde)=a+f(bcde)
2 f(bcde)=b+f(cde)
3 f(cde)=c+f(de)
4 f(de)={de,ed}

定义:

  • f(abc) : abc的全排列
  • d+f(abc) : d插入到f(abc)全排列的所有字符串的任意位置

3.伪代码实现

1 FullPermutation(A, p, r)
2 if r-p <=1
3     add(set, A[pr])
4     add(set, A[rp])
5     return set
6 return A[p] + FullPermutation(A, p+1, r)

全排序一个完整的字符数组A,最初的调用是FullPermutation(A, 0, length[A]-1)。

定义:

  • A : 带全排列的字符数组
  • p, r : 待全排列的子数组下标
  • set : 存放全排列的集合
  • add : 为set增加一个字符串

时间复杂度:O(n!)

4.Java代码实现

伪代码写算法的好处:不用关心代码的细节,便于理解和记忆。

 1 import java.util.HashSet;
 2 import java.util.Set;
 3 
 4 public class FullPermutation {
 5     public static void main(String[] args) {
 6         char[] A = "abcd".toCharArray();
 7         Set<String> set = fullPer(A, 0, A.length - 1);
 8         System.out.println("set:" + set + "\nSize:" + set.size());
 9     }
10 
11     /**
12      * @param A 待全排列的字符数组
13      * @param p 子数组左边界
14      * @param r 子数组右边界
15      * @return 全排列的集合
16      */
17     static Set<String> fullPer(char[] A, int p, int r) {
18         if (r - p <= 1) {
19             char[] cs = new char[2];
20             cs[0] = A[p];
21             cs[1] = A[r];
22             Set<String> set = new HashSet<String>();
23             set.add(new String(cs));
24             cs[0] = A[r];
25             cs[1] = A[p];
26             set.add(new String(cs));
27             return set;
28         }
29         return insertChar(A[p], fullPer(A, p + 1, r));
30     }
31 
32     /**
33      * 将字符 c 插入到集合setIn所有字符串的任意位置
34      * @param c char
35      * @param setIn Set<String>
36      * @return  Set<String>
37      */
38     private static Set<String> insertChar(char c, Set<String> setIn) {
39         Set<String> set = new HashSet<String>();
40         for (String s : setIn) {
41             char[] cs = s.toCharArray();
42             int len = cs.length + 1;
43             char[] result = new char[len];
44             for (int i = 0; i < len; i++) {
45                 result[i] = c;
46                 for (int j = 0, k = 0; k < len - 1; j++, k++) {
47                     if (j == i)
48                         j++;
49                     result[j] = cs[k];
50                 }
51                 set.add(new String(result));
52             }
53         }
54         return set;
55     }
56 }
View Code

5.更上一层楼

有一种算法可以得到排序字符串的下一个字典序,利用它,可以得到字符串的全排列。

求字典序的算法叫做康托集。

参考:如何找出字符串的字典序全排列的第N种

6.More(参考此博文的介绍)

这种类型的题目推广开来就是:求一个元素组中,所有满足一定条件的排列。

对于这种问题,在没有很好的剪枝的前提下,往往采用先求出所有排列,然后一一检验是否满足条件。

类似的题目还有八皇后问题,求所有八皇后的排放方式。

posted on 2014-09-25 10:32  BYRHuangQiang  阅读(4516)  评论(0编辑  收藏  举报

导航