题目描述
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入描述:
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
递归的思想:
同剑指offer:把数组排成最小的数(含数组的全排列)_orangefly0214的博客-CSDN博客 思路一
解题思路:
我们可以把一个字符串看成由两部分组成:第一部分为它的第一个字符,第二部分是后面的所有字符。在下图中,我们用两种不同的背景颜色区分字符串的两部分。
step1:把字符串分为两部分,一部分是字符串的第一个字符,另一部分是第一个字符以后的所有字符(有阴影背景的区域)。
step2:接下来求阴影部分字符串的排列,拿第一个字符和后面的字符逐个交换。
具体分为:(本图摘自牛客)
思路1:
处理步骤简述如下:
①j=0,swap(ch,0,0)
②j=1,swap(ch,0,1)
③j=2 swap(ch,0,2)
Python 版本实现:
思路:递归,固定住其中一个字符,剩下的字符求全排列 递归结束条件:字符串长度为1时,结束 递归过程:每次选择固定住字符串中的一个字符,对于剩下的字符做全排列
Python实现:
def permutaion(input):
if len(input) <= 1:
return input
res = set()
for i in range(len(input)):
fixed = input[i] # 字符串中选择一个字符进行固定
not_fixed = input[:i] + input[i + 1:] # 对未规定的字符递归的进行全排列
for per_res in permutaion(not_fixed):
res.add(fixed + per_res)
return sorted(res)
Java版本实现
实现1:一版比较清晰的代码实现
思路2:
利用回溯思想找到一个字符数组的全排列,并完成去重和字典排序操作。
step1:确定第i个字符,(从i到最后完成遍历枚举)。
step2:对i+1到N-1个字符递归使用全排列(缩小范围),此处就是dfs的思想。
期间利用set去重,利用Collections的sort方法完成排序。
实现2:
思路三、字典序法
字典序法
对给定的字符集中的字符规定了一个先后关系,在此基础上规定两个全排列的先后是从左到右逐个比较对应的字符的先后。
列如:对a、b、c进行排序的结果是{a,b,c}、{a,c,b}、{b,a,c}、{b,c,a}、{c,a,b}、{c,b,a}
字典序法的优点是排列的结果按照顺序输出并且对于重复的元素不进行重复排序。
字典排序法的思想:
例如:对元素1,2,3,4进行排序,假设默认的数组顺序为{1,2,3,4},先输出第一个排列:1、2、3、4。然后从右向左找到第一个非递增的数,4,3,因为3比4小,交换3、4,并且对3后面的数进行逆序排列,第二个排列为{1,2,4,3},再从右向左3,4,2,发现2比4小,交换从右向左第一个比2大的数,交换后{1,3,4,2}再对3后面的数进行逆序排列第三个序列为:{1,3,2,4}
依次循环直到数组成为完全递减数组结束1、2、3、4字典排序的最大序列为{4,3,2,1}。
实现流程如下:
假设这n个数的某一个排列为 P: P1 P2 P3...Pj-1 Pj Pj+1...Pk-1 Pk Pk+1...Pn
1.从该序列的最右端开始向左找出第一个比与自己相邻的右边数小的数,记其下标为j,即j = max{i|Pi<Pi+1}.
2.找出Pj右边第一个比Pj大的数Pk.
3.交换Pj,Pk.此时序列变为 P’: P1 P2 P3...Pj-1 Pk Pj+1...Pk-1 Pj Pk+1...Pn
4.将Pj+1...Pn 倒转,即得到此序列的后一个序列 P”: P1 P2 P3...Pj-1 Pn...Pk+1 Pj Pk-1...Pj+1
例:
1 2 3 5 7 4 6 10 9 8为1-10的一个排列
1.从该序列的最右端开始向左找出第一个比与自己相邻的右边数小的数6,其下标为7
2.6右边比6大的最小数为8
3.交换6,8得到1 2 3 5 7 4 8 10 9 6
4.将P8-P10倒转得到:1 2 3 5 7 4 8 6 9 10即为下一个序列
实现:
剑指offer:
import java.util.ArrayList;
import java.util.Arrays;
public class Solution {
ArrayList<String> ret=new ArrayList<>();
public ArrayList<String> Permutation(String str)
{
if(str==null||str.trim().length()==0){
return ret;
}
if(str.length()==1){
ret.add(str);
return ret;
}
char[] chs=str.toCharArray();
Arrays.sort(chs);
//先对数组的元素进行依次排序
while(true)
{
// System.out.println(chs);
ret.add(new String(chs));
int j;
int index=0;
for(j=chs.length-2;j>=0;j--)
{
if(chs[j]<chs[j+1])
{
index=j;
break;
//从右向左找到第一个比后一个数小的数
}else if(j==0){
return ret;
}
}
for(j=chs.length-1;j>=0;j--)
{
if(chs[j]>chs[index])
break;
//从右向左找到第一个比上面找到的数大的数
}
Swap(chs,index,j);
//交换找到的两个元素
Reverse2(chs,index+1,chs.length-1);
//对找到的那个数所在的位置后面的数组进行逆序排列
}
}
private void Reverse2(char chs[],int i,int j)
{
while(i<j){
char temp=chs[i];
chs[i]=chs[j];
chs[j]=temp;
i++;
j--;
}
}
private void Swap(char chs[],int i,int j)
{
char temp;
temp=chs[i];
chs[i]=chs[j];
chs[j]=temp;
}
}
参考: