字符串的全排列算法

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

思路
这是一个递归求解的问题,递归求解的四个特点:
1、必须有可达到的终止条件,否则程序陷入死循环
2、子问题在规模上比原问题小
3、子问题可通过再次递归调用求解
4、子问题的解应能组合成整个问题的解

对于字符串的排列问题:
如果能生成n-1个元素的全排列,就能生成n个元素的全排列。对于只有一个元素的集合,可以直接生成全排列。所以全排列的递归终止条件很明确,只有一个元素时。我们可以分析一下全排列的过程:
首先,我们固定第一个字符a,求后面两个字符bc的排列
当两个字符bc排列求好之后,我们把第一个字符a和后面的b交换,得到bac,接着我们固定第一个字符b,求后面两个字符ac的排列
现在是把c放在第一个位置的时候了,但是记住前面我们已经把原先的第一个字符a和后面的b做了交换,为了保证这次c仍是和原先处在第一个位置的a交换,我们在拿c和第一个字符交换之前,先要把b和a交换回来。在交换b和a之后,再拿c和处于第一位置的a进行交换,得到cba。我们再次固定第一个字符c,求后面两个字符b、a的排列
既然我们已经知道怎么求三个字符的排列,那么固定第一个字符之后求后面两个字符的排列,就是典型的递归思路了

下面这张图很清楚的给出了递归的过程:
递归过程
去重问题:

由于全排列就是从第一个数字起,每个数分别与它后面的数字交换,我们先尝试加个这样的判断——如果一个数与后面的数字相同那么这两个数就不交换了。
       例如abb,第一个数与后面两个数交换得bab,bba。然后abb中第二个数和第三个数相同,就不用交换了。
       但是对bab,第二个数和第三个数不 同,则需要交换,得到bba。由于这里的bba和开始第一个数与第三个数交换的结果相同了,因此这个方法不行。
       换种思维,对abb,第一个数a与第二个数b交换得到bab,然后考虑第一个数与第三个数交换,此时由于第三个数等于第二个数,所以第一个数就不再用与第三个数交换了。再考虑bab,它的第二个数与第三个数交换可以解决bba。此时全排列生成完毕!

代码如下:

import java.util.*;
public class Solution {
    public ArrayList<String> Permutation(String str) {
        ArrayList<String> list = new ArrayList<>();
        if(str == null || str.length() == 0) return list;
        permutationHelper(str.toCharArray(),0,list);
        Collections.sort(list);
        return list;
    }
    
    public void permutationHelper(char[] chars, int begin, ArrayList<String> list) {
        if(begin == chars.length - 1) {
            list.add(String.valueOf(chars));
        }else{
            Set<Character> set = new HashSet<>();//判断是否有重复的字母
            for(int j = begin; j < chars.length ; j++) {
                if(j == begin || !set.contains(chars[j])) {
                    set.add(chars[j]);
                    swap(chars,begin,j);
                    permutationHelper(chars,begin+1,list);
                    swap(chars,j,begin);
                }
            }
        }
    }
    
    private void swap(char[] chars, int i, int j) {
        char tem = chars[i];
        chars[i] = chars[j];
        chars[j] = tem;
    }
}

还可以利用set集合的去重性去掉重复的字符串

原文链接:https://blog.csdn.net/wzy_1988/article/details/8939140

猜你喜欢

转载自blog.csdn.net/machine_Heaven/article/details/104055320