1. 什么是全排列
全排列是指:对给定一个字符串,求出该字符串中字符的所有排列。
例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
2. 全排列的字典序排列算法
对给定的字符串,按照字典序输出该字符串的全排列。
下面通过以字符串{1,2,3}为例,说明字典序的全排列思路:
首先,在{1,2,3}的字典序全排列如下:
123
132
213
231
312
321
其实,字符串的全排序其实与我们平常的习惯写法一致。假如我们手写一个字符串的全排列,习惯上也会按照上面的次序写出来。那么,就示例中的{1,2,3}字符串,可以是将字符串看成是是一个数字,将数字不重复地从小到大顺序写出来而已。
那么,求字符串的字典序全排列其实就是求某个字符串的下一个字典序字符串,循环递推即可。
那么假设当前的字符串为123459876,那么它的下一个字典序字符串怎么求呢?
首先,从后往前遍历字符串123459876,找到第一个变小的字符所在位置:
1, 2, 3, 4, 5 < 9 > 8 > 7 > 6
那么字符5所在位置即为第一个变小的字符所在位置,因为从后往前到字符9都是递增;
那么,其实可以这样想,从后往前一直是递增,说明该字符串已经是以12345为前缀的最大字符串,那么下一步:
从5字符所在位置往后找,找到比5大的最小字符所在位置,就是字符6所在位置,将这两个位置上的字符相互调换,即字符5和字符6互换;
那么互换之后为:
1 2 3 4 6 9 8 7 5
字符6后面的序列从前往后仍然是维持递减的,需要将字符6后面的序列进行倒序排列为:
1 2 3 4 6 5 7 8 9
那么该字符串就是以12346为前缀的最小字符串,123465789就是123459876的下一个字典序字符串。
这样就转换为求123465789的下一个字典序字符串。
一开始将字符串进行从小到大排序,通过上述的循环求解,便能得到所有的字典序字符串排列。
字典序排列算法对包含重复字符的字符串也是适用的。
算法的实现原代码如下:
public ArrayList<String> solution(String s){
ArrayList<String> list=new ArrayList<String>();
if(s==null || s.length()==0)
return list;
char[] cc=s.toCharArray();
Arrays.sort(cc);
list.add(new String(cc));
while(true){
int p=cc.length-1;
int q;
while(p>=1 && cc[p-1]>=cc[p])
p--;
if(p==0)
break;
q=p-1;
while(p<cc.length && cc[p]>cc[q])
p++;
p--;
swap(cc,q,p);
reverse(cc,q+1);
list.add(new String(cc));
}
return list;
}
public void swap(char[] cc, int idx1, int idx2){
char c=cc[idx1];
cc[idx1]=cc[idx2];
cc[idx2]=c;
}
public void reverse(char[] cc, int idx){
int l=cc.length-1;
while(idx<=l){
swap(cc,idx,l);
l--;
idx++;
}
}