php 实现的字典序排列算法,字典序的一个生成算法

字典序的一个生成算法。最近在LeetCode刷题,刷到一个题,链接:https://leetcode-cn.com/problems/permutation-sequence/这个题要求得长度为n的字典序列的第k个排列。我们知道,字典序列是一个长度为n(n>=1),元素为1~n的无重复整数序列。之前还真没仔细了解过如何按照顺序,从小到大生成这个序列。这次就探究一下。我先在纸上枚举了n=3、4...
摘要由CSDN通过智能技术生成

字典序的一个生成算法。

最近在LeetCode刷题,刷到一个题,链接:

https://leetcode-cn.com/problems/permutation-sequence/

这个题要求得长度为n的字典序列的第k个排列。

我们知道,字典序列是一个长度为n(n>=1),元素为1~n的无重复整数序列。

之前还真没仔细了解过如何按照顺序,从小到大生成这个序列。这次就探究一下。

我先在纸上枚举了n=3、4、5这几种简单的序列的生成,从中找到规律,然后推理出一般方法。

以n=4为例,字典序从小到大生成如下:

1234 → 1243 → 1324 → 1342 → 1423 → 1432 → 2134 → 2143 → 2314 → 2341 → 2413 → 2431 → 3124 → 3142 → 3214 → 3241 → 3412 → 3421 → 4123 → 4132 → 4213 → 4231 → 4312 → 4321

当我们拥有了从第m个排列到m+1个排列的生成方法时,就可以写一个算法findNext(),通过k-1次生成排列,就可以求出第k次的排列。

那么接下来就是寻找字典序的规律:

我们能够知道 如果当前字典序排列为M,假设M的下一个字典序为N,N也有下一个字典序O,那么有以下推论:

1. N = findNext(M)

2. O = findNext(N)

3. M < N < O

所以可得:N是大于M的最小的排列

既然我们要生成这样的一个排列,那么就要尽可能变动位数更低的数去增大序列:

以 findNext(1243)为例,为了尽可能变动位数更低的数去增大序列,由于“43”已经是降序排列的子序列,无法通过变动“4”这个位及更低的位去增大序列,那么只能从上一位“2”去增大序列,所以我们要从“43”这个降序序列中找到一个最的数“3”,换到“2”的位置,把“2”放入降序序列中,然后重新按照升序排序,这样就生成了“1324”,即1324 = findNext(1243)

所以我们有以下思路:

1. 从最低位开始寻找最长的递减序列L的最高位i

2. 如果i是最高位,证明已经是最大的字典序,算法结束;如果不是,取i的上一位j,从L中找到大于j的最小值k,然后交换jk位置

3. 对L进行升序排序,把L变为最小序列

Java代码如下:

public class GetPermutation {

public static String getPermutation(int n, int k) {

if(n <= 0 || k <= 0){

return "";

}

int[] array = new int[n];

for (int i = 0; i < n; i++) {

array[i] = i + 1;

}

for (int i = 1; i < k; i++) {

findNext(array);

}

return intArrayToString(array);

}

public static void findNext(in

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值