字符串全排列(字典序法)

字典序求字符串全排列:

要求 123456789 这个序列的全排列时,我们可以知道这个序列的取值范围

范围:123456789-987654321

如何进一步在这个范围内生成我们所需要的所有序列

思想:让连续的两个子序列的公共前缀尽可能的长

比如:当生成序列为 123456978,那么下一个序列是多少呢?当然是:123456987了
这样下来,就可以一个序列接着一个序列生成,最后生成所有的全排列的所有序列了

算法步骤 

 

算法案例:

对于 346987521 下一个排列是什么?

从后向前找到第一个 arr[i] < arr[i+1],也就是递减位置,找到 6 的位置为递减的位置,因为 6 < 9 且 9 前面的都是递增的序列

再从后向前找到第一个 arr[j] > arr[i],也就是比 6 大的第一个数字,找到 7,因为 7 > 6 且 7 后面的都小于 6

将 7 和 6 调换位置得到序列:347986521

再将 7 所在位置的后缀(不包含 7)反转,从而得到:347125689

这样就得到了 346987521 的下一个排列:347125689

那么什么时候是结束呢?

当从后向前查找发现这个序列是一个递增序列的时候就结束了(因为已经到了生成序列的最大值了)

注意要点:要求一个字符串的全排列时,首先要对这个字符串内部字符进行排序,从而得到生成序列的最小值

算法实现代码:

import java.util.Arrays;

public class Test {
    public static void main(String[] args) throws Exception {
        char[] arr = "abc".toCharArray();
        Arrays.sort(arr);
        while (permutationByDictionary(arr)) {}
    }

    private static void swap(int m, int n, char[] arr) {
        char temp = arr[m];
        arr[m] = arr[n];
        arr[n] = temp;
    }

    private static void func(int index, char[] arr) {
        if (index == arr.length - 1) {
            System.out.println(new String(arr));
        } else {
            for (int i = index; i < arr.length; i++) {
                swap(index, i, arr);
                func(index + 1, arr);
                swap(index, i, arr);
            }
        }
    }

    private static boolean permutationByDictionary(char[] arr) {

        // 打印
        System.out.println(Arrays.toString(arr));

        // 从右向左找到第一个满足 arr[i] < arr[i+1] 的元素的下标 i
        int i;
        boolean isExist = false;
        for (i = arr.length - 2; i >= 0; i--) {
            if (arr[i] < arr[i + 1]) {
                isExist = true;
                break;
            }
        }
        if (!isExist) {
            return false;
        }

        int j;
        // 从数组最后一个位置,从右向左找到第一个满足 arr[j] > arr[i] 的元素的下标 j
        for (j = arr.length - 1; j > i; j--) {
            if (arr[j] > arr[i]) {
                break;
            }
        }

        // 交换 arr[i] 和 arr[j]
       swap(i, j, arr);

        // 将下标为 i 后的所有元素进行反转操作,不包括(arr[i])
        char[] temp = new char[arr.length];
        int len = 0;
        for (int k = i + 1; k < arr.length; k++) {
            temp[len++] = arr[k];
        }
        for (int k = len - 1, n = i + 1; k >= 0; k--, n++) {
            arr[n] = temp[k];
        }

        return true;
    }

}

 本篇就到这里了,如果有不清楚的地方,可以在下面评论,我会一一作出回复

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以使用递归的方来求解全排列。具体步骤如下: 1. 将字符串分为两部分:第一个字符和剩余的字符。 2. 对剩余的字符进行全排列,得到所有可能的排列。 3. 将第一个字符插入到每个排列的不同位置,得到新的排列。 4. 将所有排列按照字典序从小到大排序,输即可。 代码实现如下: ```python def permutation(s): if len(s) == 1: return [s] res = [] for i in range(len(s)): for j in permutation(s[:i] + s[i+1:]): res.append(s[i] + j) return sorted(res) s = input() print(permutation(s)) ``` 例如,对于字符串 "abc",输为 ["abc", "acb", "bac", "bca", "cab", "cba"]。 ### 回答2: 全排列是指将一组元素进行所有可能的排列,无重复。字符串全排列即为将字符串所有字符按照不同的顺序排列组合,得到的所有结果均不会重复。 求字符串全排列可以使用递归的方。首先选择一个元素作为第一个字符,然后递归求解剩下字符的全排列,最后将该字符插入到已求得的全排列的各个位置,形成新的全排列。 下面是求全排列的伪代码: 1. 输入字符串str 2. 定义函数permute(str, index),其index表示当前处理到的字符位置 3. 如果index == strlen(str),表示已求得一种排列,输该排列 4. 否则,对i从index到strlen(str)-1,依次处理以下步骤: 5. 交换str[index]和str[i] 6. 调用permute(str, index+1) 7. 交换str[index]和str[i](恢复原状态) 8. 主程序调用permute(str, 0) 以下是求字符串全排列的Python代码实现: def permute(str, index): if index == len(str): print ''.join(str) else: for i in range(index, len(str)): str[index], str[i] = str[i], str[index] permute(str, index+1) str[index], str[i] = str[i], str[index] str = raw_input('Enter string: ') permute(list(str), 0) 需要注意的是,在求解全排列时,为了避免重复,需要在交换字符前判断该字符是否已经在排列现过,若现过则不再交换。此外,为了保证输按照字典序从小到大排列,可以先将字符串进行排序。 ### 回答3: 全排列问题是经典的组合数学问题,给定一个字符串,需要把其的字符进行全排列,并按照字典序从小到大输。本题是一个递归问题,可以采用回溯进行求解。 首先,我们可以设定一个递归函数,它需要接受两个参数:字符串s和一个起始索引index。然后,我们定义一个base case,即当 index 的值等于字符串s的长度减一时,表示已经生成了一种排列,需要把它输并返回。 当 index 的值小于字符串s的长度减一时,我们需要遍历字符串从index开始的每一个字符,并把它们与第index个字符进行交换,然后递归调用该函数,同时把 index 值加一,即找到下一个位置上的字符,继续进行处理。当递归调用结束后,需要恢复字符串s的原始状态。 最后,按照字典序从小到大输全部解即可。 示例代码如下: ``` void permutation(string s, int index) { // base case if (index == s.length() - 1) { cout << s << endl; return; } // recursive case for (int i = index; i < s.length(); i++) { // swap characters swap(s[index], s[i]); permutation(s, index + 1); // restore original order swap(s[index], s[i]); } } int main() { string s = "abc"; sort(s.begin(), s.end()); // sort string in ascending order permutation(s, 0); return 0; } ``` 对于给定的字符串,我们可以先对它进行排序,保证输结果的字典序是从小到大的。然后,调用递归函数,从第一个字符开始进行全排列。最终,所有的排列都会被输。 该算的时间复杂度为 O(n×n!),其 n 为字符串的长度。因此,对于较长的字符串,需要考虑更高效的算实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值