• 面试:字符串的全排列


    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 + "
    Size:" + 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(参考此博文的介绍)

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

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

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

  • 相关阅读:
    Reactor系列(十一)take获取
    Reactor系列(十)collectMap集合
    Reactor系列(九)collect集合
    C++线程安全队列
    C++编辑编译链接运行
    C++函数的返回值——返回引用类型&,非引用类型
    关于通过在代码中执行shell脚本启动其他应用方法
    linux指令中单杆和双杠区别
    关于浏览器屏蔽掉百度右侧广告热搜的方法
    C#异步方法 async、await用法和解析
  • 原文地址:https://www.cnblogs.com/byrhuangqiang/p/3992234.html
Copyright © 2020-2023  润新知