剑指Offer 38、字符串的排列

93 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情

题目:输入一个字符串,要求输出这个字符串中字符的所有可能的排列。可以按照任意顺序返回这个字符串数组,但数组中不能包含重复元素。

解题思路

本题是一个典型的全排列问题,我们可以注意到本题需要解决的问题:

  1. 获取由字符串组成的字符数组的全部可能的排列。
  2. 保证排列不能重复。

对于第二个问题,我们可以采用HashSet来保存最终的结果,这样就能保证排列是无重复的,并且最终要求返回的是String数组,通过set.toArray也可以简单得到我们的结果。对于第一个问题,获取字符数组的全排列我们可以使用回溯法来解决,所需要注意的是在回溯过程中我们需要判断当前的元素是否已经访问过,最常见的方式就是采用一个visited数组来记录每个元素的访问情况,数组中的元素为true或false。除此之外,我们需要使用另一个数据结构来保存回溯过程中的每个字符,该数据结构应该具有简单易操作,且可以删除最后的元素的特性(回溯需要满足),满足条件的数据结构有链表,数组以及StringBuilder等,此处选用的是StringBuilder,当StringBuilder的长度达到字符串的长度时即本次回溯完成,将结果加入set即可,之后更新StringBuilder。

public String[] permutation(String s) {
    char[] array = s.toCharArray();
    boolean[] visited = new boolean[array.length];
    HashSet<String> set = new HashSet<>();
    StringBuilder sb = new StringBuilder();
    permutation(array, visited, set, sb);
    return set.toArray(new String[0]);
}

public void permutation(char[] array,boolean[] visited, HashSet<String> set, StringBuilder sb){
    if(sb.length()==array.length){
        set.add(sb.toString());
        sb = new StringBuilder();
    }

    for(int i=0;i<array.length;i++){
        if(!visited[i]){
            sb.append(array[i]);
            visited[i] = true;
            permutation(array, visited, set, sb);
            sb.deleteCharAt(sb.length()-1);
            visited[i] = false;
        }
    }
}

时间复杂度为O(nn!)O(n*n!)