leetcode60 第k个排列——康托变换与逆康托变换

leetcode60 第k个排列——康托变换与逆康托变换

康托变换:

给定从1到n的n个自然数,将这些自然数的全排列按字典序从小到大排列,如何写出第k大的那个排列?

自然,最开始的思路是直接按照字典序写出所有的排列,返回其第k个,但是这样时间和空间复杂度应该都会很大。

这个问题是一个比较封闭问题,能不能直接找到所有的排列及其顺序的一个一一映射公式呢?康托排列就解决了这一问题。

https://www.zhihu.com/search?type=content&q=康托展开%20老王

对于1到n这n个从小到大排列的数字序列,我们每次选取其中的一个数字,同时记录下这个被选取的数字在序列中的位置(从0开始),并将其拿出序列,剩下的元素顺序递补。将序列中所有的数字都拿出来后,我们就得到了一个位置序列,这个序列称为次序序列。次序序列和所有排列是按照字典序一一对应的。

接下来只需将次序序列与自然数再次进行按照顺序的一一对应就可以了。可以看到,次序序列中从低位到高位,数字的最大取值值是从0到n-1,因此可以用一个计算机中多维数组的储存方式来进行分析。想象一个维度从低到高分别是1,…,n的多维数组,我们想知道一个给定下标的元素究竟位于线性排列存储单元的内存中的什么位置,那么对于该元素的每个维度而言,假设该维度是第k维,每个这个维度的一个存储单元包含的存储块就刚好是(k-1)!个,按照从高维到低维的顺序把所有维度的存储块个数加起来,就得到了该元素的物理位置。这刚好就是次序序列与自然数的一一对应。

设次序序列为AnAn-1An-2…A1,其中Ak的取值范围为0到Ak-1,则对应的自然数应该是:An*(n-1)! + An-1*(n-2)! + … + A1*0!。

同样的道理,给定自然数,也可以得到次序序列,接着还原出排列。

代码:

class Solution {

    int[] sq = new int[10];

    public String getPermutation(int n, int k) {
        k -= 1;
        for(int i = n; i >= 1;i--){

            int fac = 1;

            for(int j = 1;j <= i-1;j++){
                fac *= j;
            }

            sq[n-i] = k / fac;
            k = k % fac;
        }

        List<Integer> tmp = new ArrayList<>();
        for(int i = 1;i <= n;i++){
            tmp.add(i);
        }

        String res = "";

        for(int i = 0;i < n;i++){
            res += tmp.get(sq[i]);
            tmp.remove(sq[i]);
        }

        return res;
    }
}

2ms 35.9MB

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
KMP算法是一种字符串匹配算法,用于在一个文本串S内查找一个模式串P的出现位置。它的时间复杂度为O(n+m),其中n为文本串的长度,m为模式串的长度。 KMP算法的核心思想是利用已知信息来避免不必要的字符比较。具体来说,它维护一个next数组,其中next[i]表示当第i个字符匹配失败时,下一次匹配应该从模式串的第next[i]个字符开始。 我们可以通过一个简单的例子来理解KMP算法的思想。假设文本串为S="ababababca",模式串为P="abababca",我们想要在S中查找P的出现位置。 首先,我们可以将P的每个前缀和后缀进行比较,得到next数组: | i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | | --- | - | - | - | - | - | - | - | - | | P | a | b | a | b | a | b | c | a | | next| 0 | 0 | 1 | 2 | 3 | 4 | 0 | 1 | 接下来,我们从S的第一个字符开始匹配P。当S的第七个字符和P的第七个字符匹配失败时,我们可以利用next[6]=4,将P向右移动4个字符,使得P的第五个字符与S的第七个字符对齐。此时,我们可以发现P的前五个字符和S的前五个字符已经匹配成功了。因此,我们可以继续从S的第六个字符开始匹配P。 当S的第十个字符和P的第八个字符匹配失败时,我们可以利用next[7]=1,将P向右移动一个字符,使得P的第一个字符和S的第十个字符对齐。此时,我们可以发现P的前一个字符和S的第十个字符已经匹配成功了。因此,我们可以继续从S的第十一个字符开始匹配P。 最终,我们可以发现P出现在S的第二个位置。 下面是KMP算法的C++代码实现:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值