要准备找工作了,得开始复习数据结构和算法基础了,最近看到全排列的问题,百度一下,看到了一博主依据交换的思想用c++实现了全排列。参见
1.不重复字符串获取全排列
个人觉得这种交换的思想相对还是难懂一点,不妨再换一种思维方式,以使得算法更加的“递归”。
思考:
要获取字符串s的全排列,就是从s中抽取一个子字符之后,再获取从s中除去该字符的字串s1的全排列。这样一想,岂不是更加容易理解,更加递归。下面贴出java版的源代码。
/**
* 获取一个字符串的全排列,设置两个参数是为了方便递归
* @param done 已经排列好的部分
* @param toBeDone 未排列好的部分
*/
public void getFullPermutation(char []done,char []toBeDone){
if(toBeDone.length==0){
System.out.println(new String(done));
return ;
}
for(int i=0;i<toBeDone.length;i++){
char []newDone=new char[done.length+1];
char []newToBeDone=new char[toBeDone.length-1];
//增加一个元素
System.arraycopy(done, 0, newDone, 0, done.length);
newDone[done.length]=toBeDone[i];
//减去一个元素
System.arraycopy(toBeDone, 0, newToBeDone, 0, i);
System.arraycopy(toBeDone, i+1, newToBeDone, i, toBeDone.length-i-1);
getFullPermutation(newDone,newToBeDone);
}
}
上述代码中使用了System的arrayCopy函数来拷贝数组
2.重复字符串获取全排列
对于重复的字符串,上述方法则会产生重复的排列,原因是:例如对于字符串abbc,加入现在要获取长度为3的子字符串的全排列,则会在取出一个字符b后,两次对子字符串abc进行全排列运算。
解决的思路是:
对待排序的字符串进行排序,这样相同的字符串就会挨在一起,接着在获取子字符串的全排列之前,先检查这个子字符串是否与上一个进行全排序的子字符串相同,如果相同,则跳过,不获取该子字符串的全排列,否则获取。
代码如下:
/**
* 获取一个字符串的全排列,设置两个参数是为了方便递归,第一次运算时,第一个参数应当设置为new char[0]
* @param done 已经排列好的部分
* @param toBeDone 未排列好的部分
*/
public void getNonRepeatFullPermutation(char []done,char []toBeDone){
//长度为0,表示首次进行运行,则先对字符串进行排序
if(done.length==0){
Arrays.sort(toBeDone);
}
char []lastToBeDone=null;
for(int i=0;i<toBeDone.length;i++){
char []newDone=new char[done.length+1];
char []newToBeDone=new char[toBeDone.length-1];
//增加一个元素
System.arraycopy(done, 0, newDone, 0, done.length);
newDone[done.length]=toBeDone[i];
//减去一个元素
System.arraycopy(toBeDone, 0, newToBeDone, 0, i);
System.arraycopy(toBeDone, i+1, newToBeDone, i, toBeDone.length-i-1);
// if(lastToBeDone==null||!new String(lastToBeDone).equals(new String(newToBeDone))){
if(!Arrays.equals(lastToBeDone, newToBeDone))
getNonRepeatFullPermutation(newDone,newToBeDone);
lastToBeDone=newToBeDone;
}
if(toBeDone.length==0){
System.out.println(new String(done));
return ;
}
}
上述代码中的注释部分的意思是:如果先对字符串数组进行排序,那么在后面判断子字符串是否已经进行过全排列时,就不必使用Arrays.equals来比较所含的字符是否一样,而直接可以使用String().equals方法来比较字符串是否相等(因为待进行全排列的字符串是进行排序过得),很明显后者的计算速度比前者快。
顺便贴出用jUint 4进行单元测试的代码(强烈建议在练习时使用jUint4进行测试,而不是编写main函数)
@Test
public void testGetFullPermutation(){
char []c=new char[]{'a','b','c','d','e','f','g'};
System.out.println("开始查找");
a.getFullPermutation(new char[0],c);
}
@Test
public void testGetNonRepeatFullPermutation(){
char []c=new char[]{'a','b','b','c'};
System.out.println("开始查找");
a.getNonRepeatFullPermutation(new char[0],c);
}