leetcode之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,生成指定位置的全排列。

如果采用穷举,可能会超时,虽然这里n<=9, 9!,数量也是很可观的。因此可以根据给定的k,进行范围缩减,输出结果。

下面给出详细的过程:

需要辅助空间n,给定例子,假设n=4, k=11

leetcode之Permutation Sequence解题思路_第1张图片

辅助空间c[n],存储的是当前情况下,以i(1<=i<=n)开头的最后一个字符串所在的下标,例如,当第一次迭代时,以1开头的最后一个字符串为1432,它的下标是6;以2开头的最后一个字符串是2431,它的下标是12,等等。采用这个辅助空间的作用是根据k确定落在以哪一个开头的空间内,则可以确定第一个数字,依次相同。


k=11,落在以2开头的字符串中,找到第一个字符2,将2对应的值变为0,表示2已经使用过;更改k, k = k - c[2-1]=5;更新辅助空间c[n]


这一轮对应的是第二个字符,1开始的占前两个,3开始的占中间2个,4开始的在最后两个。此时的k=5,找到位置为4,将c[4]置为0,更改k=5-4=1;

更新c[n]


这轮迭代对应的是第三个字符,此时k=1,找到1,而且此时c[1]=k,c[1]=0,终止迭代,此时c[n]里面可能还有很多不为0的值,反序打印即可得到结果。

代码如下:

public class Solution {
    public String getPermutation(int n, int k) {
        int[] c = new int[n];
        StringBuilder sb = new StringBuilder();
        int jieceng = getJieceng(n-1);
//        k = Math.abs(jieceng - k - 1);
        for(int i = 0; i < n; i++){
            c[i] = jieceng * (i + 1);
        }
        boolean flag= false;
        int level = n - 1;
        while(true){
            if(flag){
                for(int i = n-1; i >= 0; i--){//反序打印数组中剩余的值
                    if(c[i] != 0){
                        sb.append(i + 1);
                    }
                }
                break;
            }
            int i = 0;
            for(; i c[i]){//根据k找到相应的位置
                    continue;
                }else if(k == c[i]){//当k==c[i]时,所有的迭代终止
                    sb.append(i+1);
                    c[i]=0;
                	flag = true;
                	break;
                }else if(i == 0){//当i==0时,不能用k-c[i-1]得到k,此时k其实不用变化
                	level--;
                	c[i] = 0;
                	sb.append(i+1);
                	break;
                }else{
                	for(int j = i - 1; j >=0; j--){
                    	if(c[j] != 0){//更新k
                    		k = k - c[j];
                    		break;
                    	}
                    }
                    level--;
                    c[i] = 0;
                    sb.append(i+1);
                    break;
                }
                
            }
            jieceng = getJieceng(level);
            int times = 1;
            for(int j = 0; j < n; j++){//更新数组c[n]
                if(c[j] != 0){
                    c[j] = jieceng * times;
                    times++;
                }
            }
        }
        return sb.toString();
        
    }
    
    private int getJieceng(int n){//求阶层
        int sum = 1;
        for(int i = 1; i<= n; i++){
            sum *= i; 
        }
        return sum;
    }
}


你可能感兴趣的:(算法)