字符串的排列(字符串)

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

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


思路一:基于回溯法,递归

import java.util.ArrayList;
import java.util.Collections;

public class Solution {
    public ArrayList<String> Permutation(String str) {
        ArrayList<String> res = new ArrayList<>();
        if (str != null && str.length() > 0)
        {
            PermutationHelper(str.toCharArray(), 0, res);
            Collections.sort(res);
        }
        return res;
    }
    private void PermutationHelper(char[] chars, int i, ArrayList list)
    {
        if (i == chars.length - 1)
        {
            if (!list.contains(String.valueOf(chars)))
                list.add(String.valueOf(chars));
        }
        else
        {
            for (int j = i; j < chars.length; j++)
            {
                char temp = chars[i];
                chars[i] = chars[j];
                chars[j] = temp;
                PermutationHelper(chars, i + 1, list);
                char temp2 = chars[i];
                chars[i] = chars[j];
                chars[j] = temp2;
            }
        }
    }
}


思路二:递归,对字母重复的情况,一种新的写法

import java.util.ArrayList;
import java.util.Collections;

public class Solution {
    public ArrayList<String> Permutation(String str) {
        ArrayList<String> res = new ArrayList<>();
        if (str != null && str.length() > 0)
        {
            PermutationHelper(str.toCharArray(), 0, res);
            Collections.sort(res);
        }
        return res;
    }
    private void PermutationHelper(char[] chars, int i, ArrayList list)
    {
        if (i == chars.length - 1)
        {
                list.add(String.valueOf(chars));
        }
        else
        {
            for (int j = i; j < chars.length; j++)
            {
                if (j == i || chars[i] != chars[j])
                {
                    swap(chars, i, j);
                    PermutationHelper(chars, i + 1, list);
                    swap(chars, i, j);
                }
            }
        }
    }

    private void swap(char[] ch, int i, int j)
    {
        char temp = ch[i];
        ch[i] = ch[j];
        ch[j] = temp;
    }
}


思路三:迭代算法:字典生成算法

* 一个全排列可看做一个字符串,字符串可有前缀、后缀。

* 生成给定全排列的下一个排列。所谓一个的下一个就是这一个与下一个之间没有其他的。

* 这就要求这一个与下一个有尽可能长的共同前缀,也即变化限制在尽可能短的后缀上。

*839647521是1--9的排列。1—9的排列最前面的是123456789,最后面的987654321,从右向左扫描若都是增的,就到了987654321,也就没有下一个了。否则找出第一次出现下降的位置。

* 如何得到346987521的下一个:

*step1:从尾部往前找第一个P(i-1) < P(i)的位置

* 3 4 6 <- 9 <- 8 <- 7 <- 5 <- 2 <- 1

* 最终找到6是第一个变小的数字,记录下6的位置p

*step2:从i位置往后找到最后一个大于6的数

* 3 4 6 -> 9 -> 8 -> 7 5 2 1

* 最终找到7的位置,记录位置为q

*step3:交换位置p和q的值

* 3 4 7 9 8 6 5 2 1

*step4:倒序p位置后的所有数据

* 3 4 7 1 2 5 6 8 9

* 则347125689为346987521的下一个排列

import java.util.ArrayList;
import java.util.Arrays;

public class Solution {
    public ArrayList<String> Permutation(String str) {
        ArrayList<String> res = new ArrayList<>();
        if (str != null && str.length() > 0)
        {
            char[] strchar = str.toCharArray();
            Arrays.sort(strchar);
            res.add(String.valueOf(strchar));

            int len = strchar.length;
            while (true)
            {
                int p = len - 1;
                while (p >= 1 && strchar[p - 1] >= strchar[p]) p--;
                if (p == 0) break;

                int q = p;
                --p;//标志位置
                while (q < len && strchar[q] > strchar[p]) q++;
                --q;//标志位置
                swap(strchar, p, q);
                reverse(strchar, p + 1, len - 1);
                res.add(String.valueOf(strchar));
            }
        }
        return res;
    }
    private void reverse(char[] chars, int start, int end)
    {
        if (chars == null || start > end) return;
        for (int i = start; i <= start + (end - start -1) / 2 ; i++)
        {
            swap(chars, i, end - (i - start));
        }
    }
    private void swap(char[] ch, int i, int j)
    {
        char temp = ch[i];
        ch[i] = ch[j];
        ch[j] = temp;
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值