康托展开和康托逆展开解决第K个排列问题

来源:互联网 发布:淘宝显示获取店铺失败 编辑:程序博客网 时间:2024/05/07 15:04

这里写图片描述

集合{1,2,3,…,n}包含了 n!种不同的排列,将这n!种排列从小到大进行排序,某个排列为第K 个, 求K时,使用康托展开,已知K求对应的排列时,使用康托逆展开。


康托展开

对于某个排列 a1, a2, a3, .. , an ,将其存入数组s{a1,a2,a3,…,an} 求它在n!个排列中的位置k,
用RLi表示ai后面比ai小的数的个数,Ri表示ai后面的数的个数,
k -1= RL1*R1! + RL2*R2!+…+RLn*Rn!(RLn和Rn均为0,可以不用加上)
即 k-1 = RL1*(n-1)! + RL2*(n-2)!+…+RLn*0!
代码描述:

public static int consMulti(int n){        int res = 1;        for ( int i = 1;i <= n;i ++) {            res *= i;        }        return res;    }public static int kangtuo(int[] a) {        int res = -2;        for (int i = 0;i < a.length - 1;i ++) {            int temp = 0;            for ( int j = i + 1;j < a.length;j ++) {                if (a[j] < a[i])  temp ++;            }            res += temp*consMulti( a.length - i - 1);        }        return res + 1;    }   

康托逆展开

已知排列在第k个位置,求出该排列a1,a2,…,an,相当于对刚才的过程逆向求解。
新建数组s[n],依次求出a1,a2,…an放入s[n]中存放。
由于
k-1 = RL1*(n-1)! + RL2*(n-2)!+… +RLn*0!
令k = k-1,则 k = RL1*(n-1)! + RL2*(n-2)!+… +RLn*0!
此时,k已知,n已知,
RL1 = k / (n-1)!
RL1代表a1后面比a1小的数的个数,此时s[0] = a1 = RL1+1;
k = k % (n-1)!
RL2 = k / (n-2)!
RL2代表a2后面比a2小的数的个数,但是此时a2前面也可能存在比a2小的数LL2,a2 = LL2 + RL2 + 1,
0 <= LL2 <=L2(L2表示a2 左边的数的个数), 从LL2 = 0开始假设,LL2 = 0时,此时a2 = 0 + RL2 + 1,(1)遍历 a2 左边数字X,如果存在X == a2, 或者小于a2的数字个数C != LL2, 则此假设不成立,LL2 ++,回归(1),找到正确 a2 后存入s[1];
……….
依次求得Rli 并找到ai存入s[i-1];
……….
由于RLn = 0, 最后直接将{1,2,…, n} 中未出现的数字存入s[n-1];
代码如下:

public static int[] kthPermu(int n, int k) {        k -= 1;        int[] res = new int[n];        int num;        for (int i = 0; i < n - 1; i++) {            num = Math.floorDiv(k, consMulti(n - 1 - i));            if (i == 0) {                res[i] = num + 1;            } else {                for (int j = num + 1; j <= (num + i + 1); j++) {                    int leftNum = 0;                    boolean equal = false;                    for (int h = 0; h < i; h++) {                        if (res[h] < j) {                            leftNum++;                        } else if (res[h] == j) {                            equal = true;                            break;                        }                    }                    if (equal)                        continue;                    int tempJ = (leftNum + num) + 1;                    if (tempJ == j) {                        res[i] = j;                        break;                    }                }            }            k %= consMulti(n - 1 - i);        }        int last = -1;        for (int i = 1; i <= n; i++) {            boolean flag = false;            for (int j = 0; j < n - 1; j++) {                if (res[j] == i) {                    flag = true;                    break;                }            }            if (!flag) {                last = i;                break;            }        }        res[n - 1] = last;        return res;    }
0 0
原创粉丝点击