数组,字符串全排列算法分析(字典序生成法)

先看一个题:

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

输入描述: 输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。

就是输入一个字符串,按字母顺序输出全排列后的字符串。下面说一个字典序方法。

先用一个比较简单的数字字符串举例子,原理相同。假设我们给定一个数字字符串87632491,我们找出下一个比他大的字典序列。

1.从最右边往左边扫描,找到第一个数字符合如下标准,该数字的右邻比他大。从上面的例子我们能够看到,该数字是4,下标是i=5(从0开始);
2.从上面找到的数组下标i开始从左向右扫描,找到i右边比4大的元素中最小的一个。很容易的就能够找到,是1,下标j=7;
3.交换i和j位置的元素。交换后是87632194。
4.逆序i+1到n位置的元素。逆序后是87632149
5.处理后的字符串就是我们要找的下一个字典序中的字符串。回到第一步继续迭代即可找到所有排列。

    public ArrayList<String> Permutation(String str) {
         ArrayList<String> res = new ArrayList<String>();
        if (str==null||str.length()==0) {
            return res;
        }
        //将字符串转成字节数组,方便排序
        char [] a = str.toCharArray();
        //按字母表中的位置排序,如果忽略此步,会导致找到的全排列有所丢失。即给定字符串是bac,如果不重新排列成abc,那么abc-bac之间的字典序字符串会丢失
        Arrays.sort(a);
        while (true) {
            res.add(String.valueOf(a));
            int i = 0;
            //从右向左,寻找第一个比右邻小的元素,找到停止,负责一致扫描完整个数组
            for (i = a.length-2; i >=0&&a[i]>=a[i+1] ; i--);            
            int j = i;

            //如果j==-1,也就是上面的for循环没找到符合的元素,说明现在的数组从左向右是递减的,即最后一个字典序,返回整个集合
            if (j == -1) {
                return res;
            }

            //找到符合的元素j后,反向扫描,寻找比j元素大的中最小的一个。其实整个地方比较简单,我们在第一次for循环时,找到j,说明从n到j,即数组从右向左一直到j,是递增的,否则不会找到j。所以我们只需要从数组最右端先左扫描即可找到第一个比j大的,即使符合要求的。
            for (i = a.length-1; i>0&&a[i]<=a[j]; i--);         
            int k = i;

            //找到j和k元素后,交换两个元素,
            char b = a[j];
            a[j] = a[k];
            a[k] = b;

            //上面的工作我们只是找到了j位置的元素,j+1到n位置的元素还是一个递增的,不符合字典序,下面是逆序的过程
            for (int l = j+1; l < (a.length+j)/2+1; l++) {
                char c = a[l];
                a[l] = a[a.length-l+j];
                a[a.length-l+j] = c;
            }

            //全部处理完,找到所需要的字典序,在找到的字典序数组基础上,再去找下一个字典序
        }
    }

更多的方法,待更新。

后续更新————————————————–
递归的方法

// 递归的方法
    static public ArrayList<String> Permutation1(String str) {

        ArrayList<String> res = new ArrayList<String>();
        if (str == null || str.length() == 0) {
            return res;
        }
        char a[] = str.toCharArray();
        Arrays.sort(a);
        //res.add(String.valueOf(a));
        swap(a, 0, res);
        // Collections.sort(res);
        for (String s : res) {
            System.out.println(s);
        }

        return res;
    }

    static void swap(char a[], int start, ArrayList<String> res) {

        if (start == a.length-1) {
            res.add(String.valueOf(a));
        }else {
            for (int j = start; j < a.length; j++) {

                if (start==j||a[j] != a[start]) {
                    char b = a[j];
                    a[j] = a[start];
                    a[start] = b;

                    res.add(String.valueOf(a));
                    swap(a, start + 1, res);

                    b = a[j];
                    a[j] = a[start];
                    a[start] = b;
                }
            }
        }


    }

Good Good Study,Day Day Up。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值