Permutation Problems

来源:互联网 发布:python 微信告警 编辑:程序博客网 时间:2024/06/05 00:22

What inside a total permutation?

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

Level 1:
indexinitiation1121...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...nn(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);    }



0 0