美文网首页
面试题38_字符串的排列

面试题38_字符串的排列

作者: shenghaishxt | 来源:发表于2020-02-13 21:36 被阅读0次

    题目描述

    输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

    输入描述:

    输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母

    题解

    本题实际上是全排列问题,是回溯法的典型应用,在回溯法的基础加上了状态重置和剪枝。

    回溯可以理解为“恢复现场”,是为了节约时间和空间的一种技巧。回溯本质上是深度优先遍历,因为用到回溯的问题通常都是在一棵树上完成的,我们使用深度优先遍历在这棵树上寻找最终的答案。

    设置一个状态数组,初始化的时候状态数组中的元素都为false,表示所有元素都没有被选择。当选择一个元素时,就设置状态为true,表示当前元素被选择,在考虑下一个位置的时候就可以判断还剩余哪些元素可供选择。

    注意:在判断是否满足结束条件的时候,不可以直接 res.add(路径),否则最终得到的结果会全为空。这是因为DFS完成遍历之后会撤销之前所有的选择,路径在回到根节点之后为空。

    而在Java中都是值传递,在传参的过程中复制的是变量的地址。如果每次在满足结束条件的时候只是简单地 res.add(路径),这实际上所有的路径指向的都是同一块内存地址,因此在将路径添加到容器中时需要做一次深拷贝,即 res.add(new 路径)。

    给出一个回溯法的框架:

    res = []
    
    def Permutation(String):
        BackTracking()
        return res
    
    def BackTracking(选择列表, 路径, 状态):
        if 满足结束条件:
            res.add(new 路径)
            return
        for 选择 in 选择列表:
             剪枝
            做选择
            BackTracking(选择列表, 路径, 状态)
            撤销选择
    

    参考代码:

    public ArrayList<String> res = new ArrayList<>();
    
    public ArrayList<String> Permutation(String str) {
        if (str.length() == 0 || str.length() >= 9)
            return res;
        BackTracking(str, new StringBuilder(), new boolean[str.length()]);
        return res;
    }
    
    // 设置flag标志进行剪枝
    public void BackTracking(String str, StringBuilder sb, boolean[] flags) {
        if (sb.length() == str.length() && !res.contains(sb.toString())) {
            res.add(sb.toString());
            return;
        }
        for (int i = 0; i < str.length(); i++) {
            // 剪枝
            if (flags[i])
                continue;
            sb.append(str.charAt(i));
            flags[i] = true;
            BackTracking(str, sb, flags);
            sb.deleteCharAt(sb.length()-1);
            flags[i] = false;
        }
    }
    

    相关文章

      网友评论

          本文标题:面试题38_字符串的排列

          本文链接:https://www.haomeiwen.com/subject/vitcfhtx.html