【剑指offer系列】38-字符串的排列(关键字:字典序)

题目描述

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

输入描述:

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

一.图示:

在这里插入图片描述

在这里插入图片描述

二.字典序举例:
以9 6 4 8 5 2 1为例,通过字典序排序,找到下一个比它大的最小值步骤为:
  • 从右边开始找,找到第一个左边值 < 相邻右边值的值

2 < 1不满足; 5 < 2不满足; 8 < 5不满足; 4 < 8满足,找到了
这个值为4,该值对应的下标index(从左边算),i=2

  • 同样,再从右边开始找,找到第一个,值 > 上述点i=2对应4 的值

1 > 4不满足; 2 > 4不满足; 5 > 4满足,找到了
这个值为5,该值对应的下标index(从左边算),j=4

  • 交换i=2和j=4位置上的元素;再将i=2后的所有值进行倒叙

9 6 4(i=2) 8 5(j=4) 2 1 =>swap: 9 6 5 8 4 2 1
将i=2之后的所有值,8 4 2 1进行倒叙=>reverse: 1 2 4 8

  • 当值为9865421,找不到满足要求的 i ,即字典序排序,此值为后一个排序。
最终为:9 6 5 1 2 4 8,是9648521字典序排序后的值
三.结合代码:

在这里插入图片描述

public class Main38
{
    /**
     * 输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
     */
    public static ArrayList<String> permutation(String str) {

        ArrayList<String> list = new ArrayList<>();
        if (str == null || str.length() == 0)
            return list;
        char[] chars = str.toCharArray();
        char[] temp = str.toLowerCase().toCharArray();
        for (int i = 0; i < temp.length; i++)
        {
            if (temp[i] > 'z' || temp[i] < 'a')return list;
        }
        Arrays.sort(chars);//将字符数组按升序排列
        list.add(String.valueOf(chars));//先将按升序排列后的字符串存入list中
        while (true) {
            int i = chars.length - 1;
            int j = chars.length - 1;
            //1.从字符数组最后一个字符开始往前遍历,寻找第一次chars[i-1]<chars[i]的位置
            while (i >= 1 && chars[i - 1] >= chars[i]) {//i=2
                i--;
            }
            if (i == 0) {//此时的数组已经是降序排列了(从右往左都是增的),表明全排列完成,cba这种
                break;
            }
            //2.j从从最后一个位置开始,往前遍历,遇到大于chars[i-1]的值时停下
            // 注意在遇到等于chars[i-1]的值的时候一定不要停下,不然会造成死循环(因为此时交换的是值相同的两个数)
            while (j >= 0 && chars[j] <= chars[i - 1]) {
                j--;
            }
            //3.
            swap(chars, i - 1, j);//交换chars[i-1]和chars[j]的值
            reverse(chars, i);//反转包括chars[i]元素在内到数组结尾的所有元素
            list.add(String.valueOf(chars));
        }
        return list;
    }

    private static void reverse(char[] ch, int i) {
        int left = i;
        int right = ch.length-1;
        while (left <= right){
            char temp = ch[left];
            ch[left] = ch[right];
            ch[right] = temp;
            left++;
            right--;
        }
    }

    private static void swap(char[] chars, int i, int j) {
        char tmp = chars[i];
        chars[i] = chars[j];
        chars[j] = tmp;
    }

    public static void main(String[] args) {
        ArrayList<String> list = permutation("abc");
        for (String s : list) {
            System.out.println(s);
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值