数据结构与算法分析笔记与总结(java实现)--字符串1:字符串的排列(*)

来源:互联网 发布:项羽 知乎 编辑:程序博客网 时间:2024/06/06 01:30

题目:输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

何为字典序:对于若干的字符串,从左到右扫描字符,先比较第一个字符,按照第一个字符的ascii码对各个字符串进行排序,对于第一位字符相同的字符串,比较其第二个字符,按照第二个字符的ascii码进行排序,即总是按照某一个字符排序,这个字符相同的若干字符串再按照下一个字符进行进行排序。注意:在使用数组、集合的Java类库中的排序算法对字符串进行排序时就是根据字典序进行排序的,即对于一个数组[abc,cba,bca,cab,acb]或者集合{ abc,cba,bca,cab,acb },使用Arrays.sort()和Collectios.sort()本来就是按照元素的字典序进行排序的,因此本题只需要得到给定字符串str的所有可能的字符串排列组合,将其放入到一个数组result中,然后使用Collections.sort(result)对result集合进行排序即可。关键是得到字符串str所有可能的排列组合。

如何得到字符串str的所有排列组合?这个逻辑比较复杂困难,要多次理解。在实现时可以使用递归或者循环来实现,但是最好使用递归,简洁高效,面试要求掌握递归。

对于str=dcba,将str转化为char数组char[]=[d,c,b,a];构建一个方法helper()对数组进行排列组合的统计: 从第0个元素开始遍历数组,遍历d时,先将d与d交换,然后再与c交换,再与b交换,再与a交换,每一交换时使用递归来进行处理,d与d交换完成之后,然后相当于对[c,b,a]数组进行相同的处理,即对于数组[c,b,a]调用helper()方法统计其字符串的各种排列。(构建递归时,总是假设一个这个递归方法可以完成需要的功能,即对其进行调用后就可以完成需要的功能,然后再程序中需要的地方只要调用这个方法即可,然后再来写这个方法的实现逻辑,例如这里就认为helper(char,index,result)方法可以统计出char数组中从index下标开始的后面的元素构成的各种字符串组合,将其放入到result中);在对[c,b,a]进行统计时,先将c与c进行交换……然后c与b进行交换,此时数组就变成[b,c,a],保持b不变,对[c,a]进行排列组合的统计;此时先将c与c进行交换……然后将c与a进行交换,变成[c,a],保持c不变,对[a]进行排列,由于只有一个元素可以认为已经排好序了,所以此时对[a]排列可以返回,于是[c,a]的排列完成,于是[b,c,a]排序完成,然后对[b,c,a]进行相同的排列统计,再对[b,a,c]进行排序;…………

于是在保持d不变的情况下,对[c,b,a],[b,c,a],[b,a,c]以及所有子情况进行了统计,之后再统计[c,d,b,a],[b,c,d,a],[a,c,b,d]以及各种子情况。

综上所述,显然各个步骤进行的逻辑都是相同的,且本次方法的完成依赖于下一级方法的执行完成,于是显然应该使用递归来完成。构造一个递归方法helper(array,index,result),用于对数组array中从index开始到最后的元素进行排列统计,将得到的排列字符串放入到result集合中,这个递归方法的终止条件是要进行排列的元素只有一个元素的情况,即index==array.length-1;于是当index==s.length-1时本次递归结束,即完成一次字符串的排列,将这个字符串放入到结果集合result中。在对index开始的数组进行排列时,只是关注index这个元素,将其逐个与后面元素进行交换,每次交换后就需要对当前这种交换后的数组当做新的需要进行排列的子数组,对其进行新的递归调用,于是,在将index与i进行交换后就要调用helper(array,index+1,result)对index数组后面的子数组进行排列,千万注意,对于数组[d,c,b,a],在某次交换排列完成之后,要将交换的顺序恢复,因为在遍历index后面的元素时,使用的i都是相对于原来的数组[d,c,b,a]而言的,因此必须在helper()调用成功后将交换的元素重新交换回原先的位置。还要注意一点:对于index开始的与后面元素的逐个交换过程中,如果有重复的情况,即例如array[index]与后面的某个元素array[i]的值相同,那么不需要交换,交换了不产生新的排列,这个值array[index]对应的排列已经在开始时自身与自身交换时统计过了,即只有当array[index]!=array[i]时,才要将array[i]与array[index]交换,或者当i==index时也要进行交换,即自身与自身交换,就是不交换,即表示index这个元素位于当前位置的情况。

常识:数组length是属性,字符串length()是方法,集合size()是方法

//这道题目较难,要求在循环中进行递归调用。本质是求出str的所有可能排列组合,要得到字典序只需要直接调用类库中的排序方法就可以实现

import java.util.ArrayList;

import java.util.*;                            //注意包的引入

public class Solution {

    //返回的是str各种组合的字典序排列

    publicArrayList<String> Permutation(String str) {

        //特殊输入,常识:数组length是属性,字符串length()是方法,集合size()是方法

        //这里注意str.length()==0时最终result[],不是null,注意null与空值的区分

       if(str==null||str.length()<0) return null;

       

        //先将字符串转化为字符数组以便处理

        char[]array=str.toCharArray();

       

        //定义一个集合来存放各种排列的组合

       ArrayList<String> result=new ArrayList<String>();

       

        //调用方法helper来找出array数组中从0开始的所有排列,将其放入到result数组中

       this.findPermutationAfterIndex(array,0,result);

       

        //对于包含所有排列的集合直接使用Collections的方法进行排序

       Collections.sort(result);

       

        return result;

    }

   

   

    //这个方法专门用来找出数组arrayindex及之后部分数组中的排列组合,并将其放入result数组,没有返回值

    public voidfindPermutationAfterIndex(char[] array,int index,ArrayList<String>result){

        //递归的终止条件

       if(index==array.length-1){

           result.add(new String(array));

        }

       

        //如果没有终止,从index开始逐个进行交换、递归、恢复

        for(inti=index;i<array.length;i++){

            //array[index]array[i]相同时不需要交换,在自身与自身交换时已经处理过了

           if(array[index]!=array[i]||i==index){

                //交换array数组中indexi的元素

               this.swap(array,index,i);

                //index后面的数组求排列

               this.findPermutationAfterIndex(array,index+1,result);

                //恢复交换的数字

               this.swap(array,index,i);

            }

        }

    }

   

   

    //这是个辅助方法,用来交换array数组中下标为i,j的两个元素

    public voidswap(char[] array,int i,int j){

        //不会出现越界的情况

        chartemp=array[j];

       array[j]=array[i];

        array[i]=temp;

    }

}
0 0
原创粉丝点击