字符串的排列
问题描述:输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则按字典序打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入描述:输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
示例
输入:"ab"
返回值:["ab","ba"]
方法一
思路分析
本题我们能想到的最直接的办法就是利用数学中的全排列,即对于一个字符串,首先确定第一个位置的字符,使用swap交换函数依次从当前位置的字符开始遍历寻找其余字符,从而得到第一个位置字符确定的字符串,而后其余位的字符也是用相同的办法,当确定到最后一个字符时,直接将最后一个字符插入到字符串中,递归结束,输出所有的排列。
图解
输入字符串“abc”,通过递归算法输出其全排列,通过第一次swap操作得到第一个位置上的确定字符,共三种情况,而后对剩余位的确定采用同样的办法。
C++核心代码
class Solution { public: vector<string> Permutation(string str) { if(str.empty()) return {}; set<string> tmp; perm(0, str, tmp);//从第一个位置开始递归 return vector<string>({tmp.begin(), tmp.end()}); } void perm(int pos, string s, set<string> &ret) { if (pos+1 == s.length())//运行到最后一个字符结束 { ret.insert(s); return; } for (int i = pos; i < s.length(); ++i) { swap(s[pos], s[i]);//每次将当前位置的字符与后面的所有字符交换而形成不同的可能 perm(pos+1, s, ret);//相同方法排列剩余的位 swap(s[pos], s[i]);//将字符串归位 } } };
复杂度分析
- 时间复杂度:字符串全排列的组合的时间为$O(n!)$,因此时间复杂度为$O(n!)$
- 空间复杂度: 递归算法的空间复杂度为递归的深度*每次递归创建变量的个数,辅助数组tmp要放入的元素有$1+2+3+...+n=n(n-1)/2$,因此时间复杂度为$O(n^2)$
方法二
思路分析
本题可以采用字典序的方法,字典序就是说给定两个字符串,逐个字符比较,那么先出现较小字符的那个串字典顺序小,例如abc>acb,那么本题可以先将给定的字符串按照字典序的顺序排序,形成最大字典序的字符串,例如给定字符串“abdc”,则其最大字典序的字符串为“abcd”,接着寻找下一个排列组合,为“abdc”,直到下一个排列组合为空,运行结束。接下来将介绍寻找下一个排列组合算法的思想步骤。
- 首先将字符串按升序排序,找到字典序最大的字符串
- 从字符串数组尾部开始从右往左寻找两个相邻元素(必须是相邻的),左边元素为arr[i],右边元素为arr[i+1],并且arr[i]的字典序大于arr[i+1]
- 之后再从尾端开始往前检验,找出第一个字典序小于arr[i]的元素arr[j],交换两个元素
- 将arr[i]之后的所有元素颠倒排序
实例分析
给定字符串“abc”,首先按升序方式找到最大的字符串,图中对调表示尾端开始往前检验,找出第一个字典序小于arr[i]的元素arr[j],交换两个元素;重排表示arr[i]之后的所有元素颠倒排序;在此过程中将所有的排列输出
python核心代码
# -*- coding:utf-8 -*- class Solution: def Permutation(self, ss): # write code here n = len(ss) arr = list(sorted(ss)) test = list(reversed(arr)) ans = [] # 生成下一个排列 while arr != test: ans.append(''.join(arr)) i = n - 2 while i > 0 and arr[i] >= arr[i+1]:#从尾部开始往前检验,检验相邻位置的字典序大小 i -= 1 if i<0:return j = n - 1 while j > i-1 and arr[j] <= arr[i]:#找出第一个字典序小于arr[i]的元素arr[j] j -= 1 m=arr[i] arr[i]=arr[j] arr[j]=m#交换两个元素元素 arr = arr[:i+1] + sorted(arr[i+1:])#arr[i]之后的所有元素颠倒排序 ans.append(''.join(test))#在此过程中将所有的排列输出 return ans
复杂度分析
- 时间复杂度:字符串全排列的时间复杂度为$O(n!)$,因此时间复杂度为$O(n!)$
- 空间复杂度:借助于一个辅助数组存储字符串,空间复杂度为$O(n)$