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

字典序求字符串全排列:

要求 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;
    }

}

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

### 实现字符串的字典序排列 对于给定的一组字符串,要按照字典序对其进行排序,可以利用编程语言内置的排序函数来完成这一操作。大多数现代编程语言提供了可以直接使用的稳定排序方法,这些方法能够接受自定义比较器作为参数,从而允许开发者指定特定的排序逻辑,在本场景下即为依据字符编码表中的位置进行升序或者降序排列。 在Python中,可以通过`sorted()`函数轻松实现此功能[^2]: ```python def sort_strings_lexicographically(strings_list): sorted_strings = sorted(strings_list, key=str.lower) # 考虑到大小写敏感问题 return sorted_strings ``` 上述代码片段展示了如何通过调用`sorted()`并传入待排序列表以及可选的关键字参数`key`来进行区分大小写的字典序排序。这里使用了`str.lower`作为键函数以确保大写字母会被错误地认为是在小写字母之前。 如果任务扩展至从N个字符串中挑选J个字符串组合成字典序最小的结果,则涉及到更复杂的贪心策略或动态规划解法。这类问题通常需要先对输入数据集做预处理——比如整体上的初步排序;之后再考虑具体的选择机制以便构建最终所需的最优序列[^1]。 当面对全排列的需求时,意味着仅要找所有可能的同顺序安排方式,而且还要保证它们遵循一定的次序规则输,这时就需要采用递归或者其他迭代技术逐一生成候选方案直至遍历整个空间为止。C++标准库中有名为`next_permutation`的功能可以帮助简化此类工作的复杂度[^3]。 #### C++示例:获取下一个更大的字典序排列 ```cpp #include <algorithm> // 前置条件:arr已经是一个有效的排列 bool nextPermutation(vector<int>& nums){ int n = nums.size(), k, l; for (k = n - 2; k >= 0; k--) { if (nums[k] < nums[k + 1]) break; } if (k < 0) reverse(nums.begin(), nums.end()); else{ for (l = n - 1; l > k; l--){ if (nums[l] > nums[k]) break; } swap(nums[k], nums[l]); reverse(nums.begin() + k + 1, nums.end()); } } ``` 这段代码实现了寻找当前数组所能形成的下一个更大字典序排列的任务,它适用于任何类型的数值型元素组成的向量,并且可以在O(n)时间内完成转换过程。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值