Permutation Sequence

【题目】

    The set [1,2,3,…,n] contains a total of n! unique permutations. By listing and labeling all of the permutations in order, We get the following sequence (ie, for n = 3):

1. “123”
2. “132”
3. “213”
4. “231”
5. “312”
6. “321”

Given n and k, return the kth permutation sequence. Note: Given n will be between 1 and 9 inclusive.


【题意】:按照字典顺序的思想,求出n个数的全排列情况中第k个排列,最后返回形式为字符串。

【解析】

            可以一个一个的按次序求排列即利用之前的Next Permutation。

public class Solution {
    public String getPermutation(int n, int k) {
        // 初始化起始数组
        char[] init = new char[n];
        for (int i = 0; i < n; i++) {
            seq[i] = (char) ('0' + i + 1);
        }
        
        // 利用nextPermutation找到第k个
        for (int i = 1; i < k; i++) {
            nextPermutation(init );
        }
        
        return String.valueOf(init );
    }
    
    public void nextPermutation(char[] init) {
        // find the last adjacent two element that is in ascending order
        int i = init.length - 1;
        while (i > 0 && init[i - 1] >= init[i]) {
            i--;
        }
        
        if (i == 0) return;
        
        int j = init.length - 1;
        while (j >= i && init[i - 1] >= init[j]) {
            j--;
        }
        
      
        char tmp = init[i - 1];
        init[i - 1] = init[j];
        init[j] = tmp;
        
        int l = i;
        int r = init.length - 1;
        while (l < r) {
            tmp = init[l];
            init[l] = init[r];
            init[r] = tmp;
            l++;
            r--;
        }
    }
}

第二种:数学解法

在n!个排列中,第一位的元素总是(n-1)!一组出现的,也就说如果p = k / (n-1)!,那么排列的最开始一个元素一定是nums[p]。

别人的:

1. 能否直接算出集合{1, 2, ..., m}的第n个排列?

设某个集合{a1, a2, ..., am}(a1<a2<...<am)构成的某种序列pn,基于以上分析易证得:若as<at,那么将as作为第1个元素的所有序列一定都小于at作为第1个元素的任意序列。同理可证得:第1个元素确定后,剩下的元素中若as'<at',那么将as'作为第2个元素的所有序列一定都小于作为第2个元素的任意序列。例如4个数的集合{2, 3, 4, 6}构成的序列中,以3作为第1个元素的序列一定小于以4或6作为第1个元素的序列;3作为第1个元素的前题下,2作为第2个元素的序列一定小于以4或6作为第2个元素的序列。

推广可知,在确定前i(i<n)个元素后,在剩下的m-i=s个元素的集合{aq1, aq2, ..., aq3}(aq1<aq2<...<aqm)中,以aqj作为第i+1个元素的序列一定小于以aqj+1作为第i+1个元素的序列。由此可知:在确定前i个元素后,一共可生成s!种连续大小的序列。

根据以上分析,对于给定的n(必有n<=m!)可以从第1位开始向右逐位地确定每一位元素。在第1位不变的前题下,后面m-1位一共可以生成(m-1)!中连续大小的序列。若n>(m-1)!,则第1位不会是a1,n中可以容纳x个(m-1)!即代表第1位是ax。在确定第1位后,将第1位从原集合中删除,得到新的集合{aq1, aq2, ..., aq3}(aq1<aq2<...<aqm),然后令n1=n-x(m-1)!,求这m-1个数中生成的第n1个序列的第1位。

举例说明:如7个数的集合为{1, 2, 3, 4, 5, 6, 7},要求出第n=1654个排列。

(1654 / 6!)取整得2,确定第1位为3,剩下的6个数{1, 2, 4, 5, 6, 7},求第1654 % 6!=214个序列;

(214 / 5!)取整得1,确定第2位为2,剩下5个数{1, 4, 5, 6, 7},求第214 % 5!=94个序列;

(94 / 4!)取整得3,确定第3位为6,剩下4个数{1, 4, 5, 7},求第94 % 4!=22个序列;

(22 / 3!)取整得3,确定第4位为7,剩下3个数{1, 4, 5},求第22 % 3!=4个序列;

(4 / 2!)得2,确定第5为5,剩下2个数{1, 4};由于4 % 2!=0,故第6位和第7位为增序<1 4>;

 因此所有排列为:3267514。

 1:

   public String getPermutation(int n, int k) {  
        int []num = new int[n];  
            int permCount = 1;  
            for(int i=0;i<n;i++){  
                num[i] = i+1;  
                permCount*=(i+1);  
            }  
            k--;  
            StringBuilder target = new StringBuilder();  
            for(int i=0;i<n;i++){  
                permCount = permCount/(n-i);  
                int choosed = k/permCount;  
                target.append(num[choosed]);  
                for(int j=choosed;j<n-i-1;j++){  
                    num[j] = num[j+1];  
                }  
                k = k%permCount;  
            }  
            return target.toString();  
        }  

2:加了额外空间

public class Solution {
    public String getPermutation(int n, int k) {
        int data[]=new int[10];
        boolean visited[]=new boolean[10];
        data[0]=data[1]=1;
        ArrayList<Integer> list=new ArrayList<Integer>();
        for(int i=1;i<=n;i++)
        {
            data[i]=data[i-1]*(i);
            list.add(i);
        }
        String result="";
        k--;
        for(int i=n-1;i>=0;i--)
        {
            int cur=k/data[i];
            int j=1;
            for(;j<9;j++)     //从数组中 针对未访问过的元素visited[]=false  找第cur个,找到的为j
            {
                if(visited[j]==false)
                    cur--;
                if(cur<0)
                    break;
            }
            visited[j]=true;
            result+=(j);
            k=k%data[i];
        }
        return result;
    }
    
}

给定一种排列,如何算出这是第几个排列呢?

和前一个问题的推导过程相反。例如3267514:

后6位的全排列为6!,3为{1, 2, 3 ,4 , 5, 6, 7}中第2个元素(从0开始计数),故2*720=1440;

后5位的全排列为5!,2为{1, 2, 4, 5, 6, 7}中第1个元素,故1*5!=120;

后4位的全排列为4!,6为{1, 4, 5, 6, 7}中第3个元素,故3*4!=72;

后3位的全排列为3!,7为{1, 4, 5, 7}中第3个元素,故3*3!=18;

后2位的全排列为2!,5为{1, 4, 5}中第2个元素,故2*2!=4;

最后2位为增序,因此计数0,求和得:1440+120+72+18+4=1654



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值