题目:字符串排列
描述:输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串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; } }
该题应该注意一点内容是,如果两个字符相同的话,就不需要再进行交换合并了,没有意义。
解法二:
思路分析:在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代码显得轻松了许多。