题目:字符串排列

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

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

示例1输入:"ab",返回值:["ab","ba"]


解法一:
思路描述:这道题属于经典的DFS题目,其大致思想可以为,先确定第i个字符,然后将i从0到最大值完成遍历枚举,然后对i+1个字符通过递归的方式,使用全排列法实现范围的缩小。

实例分析:因为题目中只有两个字符,不太好进行分析,所以我们使用”abc”三个字符进行分析。

如图所示:

具体java代码如下所示:


 


import java.util.ArrayList;
import java.util.Collections;

public class Solution {
    public ArrayList<String> Permutation(String str) {
       ArrayList<String> res = new ArrayList<>();
        if (str == null || str.length() == 0) {
            return res;
        }
        char[] chars = str.toCharArray();
        find(res, chars, 0);
        Collections.sort(res);
        return res;
    }
    
    private static void find(ArrayList<String> res, char[] chars, int i) {
        if (i == chars.length) {
            res.add(new String(chars));
            return;
        }
        for (int j = i; j < chars.length; j++) {
            //交换
            if (chars[i] == chars[j] && i != j) { //去掉重复的 
                continue;
            }
            swap(chars, i, j);
            //确定好i的位置,对[i+1~length-1]范围内的字符数组完成全排列
            find(res, chars, i + 1);
            //恢复原数组
            swap(chars, i, j);
        }
    }
    
    private static void swap(char[] chars, int i, int j) {
        char temp = chars[i];
        chars[i] = chars[j];
        chars[j] = temp;
    }
}

该题应该注意一点内容是,如果两个字符相同的话,就不需要再进行交换合并了,没有意义。


补充说明:根据上述图所示,我们简单的进行分析一下。abc的全排列有abc、acb、bac、bca、cab、cba,采用全排列的方法,将第一个数字与每个数字后面的数字进行交换,即可得到最终结果。

解法二:

思路分析:在C++STL中提供了两个用来计算排列组合的算法,分别是next_permutation和prev_permutation,分别称做下一个排列组合和前一个排列组合,我们以{a,b,c}为例,排列组合根据已有的字符数做字典顺序的排序,也就是说当abc为开始的话,遵循着每一个元素都小于其后元素的观点,acb是下一个排列组合,它是固定了a之后做的新的排列组合,同样来说,固定b而做的排列组合为bac、bca,固定c而做的排列组合为cab、cba。next_permutation()会取得[first,last]所表示的序列的下一个排列组合,如果没有下一个排列组合,便返回false,否则返回true。

其具体C++代码为:

class Solution {
public:
    vector<string> Permutation(string str) {
        if(str.empty())
            return {};
        sort(str.begin(), str.end());
        vector<string> res;
        res.push_back(str);
        while(next_permutation(str.begin(),str.end()))
            res.push_back(str);
        return res;
    }
};

该算法可以直接调用next_permutation()做下一轮的排列组合,相比于上面的java代码显得轻松了许多。