Permutation Problems

What inside a total permutation?

首先逐级分析,给每个permutation标上唯一的索引:

Level 1:
indexinitiation
11
21
...1
(n-1)!1
(n-1)!+12
(n-1)!+22
...2
(n-1)!+(n-1)2
......
(k-1)(n-1)!k-1
(k-1)(n-1)!+1k
(k-1)(n-1)!+2k
...k
(k-1)(n-1)!+(n-1)!k
......
(n-1)(n-1)!+1n
(n-1)(n-1)!+2n
...n
n(n-1)!n

Level 2:
indexinitiation
(k-1)(n-1)!+1k1
(k-1)(n-1)!+2k1
...k1
(k-1)(n-1)!+(n-2)!k1
(k-1)(n-1)!+(n-2)!+1k2
(k-1)(n-1)!+(n-2)!+2k2
... 
(k-1)(n-1)!+(n-2)!+(n-2)!k2
......
(k-1)(n-1)!+(t-1)(n-2)!k(t-1)
(k-1)(n-1)!+(t-1)(n-2)!+1kt
(k-1)(n-1)!+(t-1)(n-2)!+2kt
......
(k-1)(n-1)!+(t-1)(n-2)!+(n-2)!kt
......
(k-1)(n-1)!+(n-1)(n-2)!+1kn
(k-1)(n-1)!+(n-1)(n-2)!+2kn
......
(k-1)(n-1)!+n(n-2)!kn

Level 3:
indexinitiation
(k-1)(n-1)!+(t-1)(n-2)!+1kt1
(k-1)(n-1)!+(t-1)(n-2)!+2kt1
...kt1
(k-1)(n-1)!+(t-1)(n-2)!+(n-3)!kt1
(k-1)(n-1)!+(t-1)(n-2)!+(n-3)!+1kt2
(k-1)(n-1)!+(t-1)(n-2)!+(n-3)!+2kt2
......
(k-1)(n-1)!+(t-1)(n-2)!+2(n-3)!kt2
......
(k-1)(n-1)!+(t-1)(n-2)!+(m-1)(n-3)!kt(m-1)
(k-1)(n-1)!+(t-1)(n-2)!+(m-1)(n-3)!+1ktm
(k-1)(n-1)!+(t-1)(n-2)!+(m-1)(n-3)!+2ktm
......
(k-1)(n-1)!+(t-1)(n-2)!+m(n-3)!ktm
......
(k-1)(n-1)!+(t-1)(n-2)!+(n-1)(n-3)!+1ktn
(k-1)(n-1)!+(t-1)(n-2)!+(n-1)(n-3)!+2ktn
......
(k-1)(n-1)!+(t-1)(n-2)!+n(n-3)!ktn

假设我们把n个数存放在数组F[n]中(初始化F[i]=i).

可见索引为K的n位的permutation所对应的第一位是F[ceil(K/(n-1)!)]

纪录下这一位以后我们进入二级子表,在子表中的索引和原索引存在类似求模的关系:
K'= K%(n-1)!==0?(n-1)!: K%(n-1)!
而对应的F' = F.remove(ceil(K/(n-1)!))

接下来重复第一步:可见索引为K的n-1位的permutation所对应的第一位是F'[ceil(K'/(n-2)!)]

按照此过程归纳到F为空,此时K permutation所有位数值已完全纪录。

Solution:

public static String getPermutation(int n, int k) {
        ArrayList<Integer> f = new ArrayList<Integer>();
        for(int i=0;i<n+1;i++) f.add(i);
        String ret="";
        int m = k;
        for(int lv = 1; lv<=n; lv++){
            int b = factorial(n-lv);
            int a = (int) Math.ceil(m*1.0/b);
            ret += f.get(a);
            f.remove(a);
            if(lv<n){
            	m = m%b==0?b:m%b;
            }
        }
        return ret;
    }

What inside a next permutation?
如果序列{a1a2a3...an}已经是非严格降序(字典序),那么这个序列就是最大的序列了。 

假如再任给一个序列X={x1x2...xm},将这个序列附在X后面,即Xa1a2a3...an. 令X'={x1x2...x_m-1}, 那么可以得知这个序列是以X'xm所引导的最大序列。

根据字典序的定义,可知对于任意序列{a1a2a3...an}:

X'sort(xm,a1,a2,a3,...,an)<X'xm sort(a1,a2,a3,...,an)<X'xm,a1,a2,a3,...,an<X'xm reverse(sort(a1,a2,a3,...,an))<X'reverse(sort(xm,a1,a2,a3,...,an))

那么,如果{xm,a1,a2,a3,...,an}是非单调的,则X'xm,a1,a2,a3,...,an的下一个序列一定是处于X'sort(xm,a1,a2,a3,...,an) 和 X'reverse(sort(xm,a1,a2,a3,...,an))之间的(包括边界)。因此一切xm之前的序列都可以不予以考虑!

现在分析xm应该和{a1a2a3...an}中的谁置换以确定下一序列的开头元素。首先可以发现,与xm置换的元素不得小于等于xm,否则置换完成以后序列排名无法提升。那么,在所有大于xm的元素中,我们一定是要选择最接近xm的。这样完成的置换可以保证是增幅最小的。

当置换完成后,我们有序列X'ai,a1,a2,a3,...,xm,...,an, 而同样的,对于这个由X' ai所引导的序列存在上下限:

X'ai sort(a1,a2,a3,...,xm,...,an)<X'ai,a1,a2,a3,...,xm,...,an<X'ai reverse(sort(a1,a2,a3,...,xm,...,an))

由之前的分析知:
xm<ai
X'xm,a1,a2,a3,...,an<X'xm reverse(sort(a1,a2,a3,...,an))<X'ai sort(a1,a2,a3,...,xm,...,an)<X'ai,a1,a2,a3,...,xm,...,an

Solution:

public static void nextPermutation(int[] num) {
        for(int i=num.length-1;i>0;i--){
            if(num[i]>num[i-1]){
                for(int j=num.length-1;j>=i;j--){
                    if(num[i-1]<num[j]){
                        int t = num[j];
                        num[j] = num[i-1];
                        num[i-1] = t;
                        /**
                         * a - the array to be sorted
                         * fromIndex - the index of the first element, inclusive, to be sorted
                         * toIndex - the index of the last element, exclusive, to be sorted
                         */
                        Arrays.sort(num,i,num.length);
                        return;
                    }
                }
            }
        }
        Arrays.sort(num);
    }



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值