Permutation Sequence

介绍了一种高效算法来找出从1到n的所有唯一排列中的第k个排列,并提供了C++和Java两种语言的实现方式。

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.

比较暴力的方法是利用之前写过的nextPermutation,但感觉应该有更好的方法吧。


class Solution {
public:
    string getPermutation(int n, int k) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        vector<int> num;
        for(int i = 1; i <= n; ++i){
            num.push_back(i);
        }
        for(int i = 1; i< k; ++i){
            nextPermutation(num);
        }
        string res;
        for(int i = 0; i < num.size(); ++i){
            res += (char)(num[i] + '0');
        }
        return res;
    }
    void nextPermutation(vector<int> &num) {    
        // Start typing your C/C++ solution below    
        // DO NOT write int main() function    
        int nSize = num.size();    
        if (nSize <= 1) return;    
            
        int idx = nSize - 1;    
        // 查找第一个下降的元素    
        while(--idx >= 0 && num[idx] >= num[idx+1]);    
        if (idx >= 0)    
        {    
            int i = nSize - 1;    
            // 查找第一个比idx所指元素大的元素    
            while(num[i] <= num[idx])    
            {    
                --i;    
            }    
            swap(num[i], num[idx]);    
            // 反转后面所有元素,让它从小到大sorted    
            reverse(num.begin()+idx+1, num.end());    
        }    
        else    
        {    
            reverse(num.begin(), num.end());    
        }    
    }
};

果然还是有其他方法的,那就是先算总共有多少种排列组合,然后看k在哪个区间,只要区间确定了,首位的值就确定了。看了个java写的,自己用c++写了一遍,之前那个方法需要1900ms,那个java的方法需要500+ms,现在这个c++实现的只需要20ms就可以过large case。

class Solution {
public:
    string getPermutation(int n, int k) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        vector<int> num;
        for(int i = 1; i<= n; ++i){
            num.push_back(i);
        }
        vector<int> cnt;
        cnt.push_back(1);
        for(int i = 1; i<=n;++i ){
            cnt.push_back(cnt[i-1] * i);
        }
        return subPermutation(num, cnt, n, k);
    }
    string subPermutation(vector<int> &num, vector<int> & cnt, int n, int k){
        if(n ==0 || k == 0){
            return "";
        }
        for(int i = 1; i<= n; ++i){
            if(k <= cnt[n-1] *i){
                int t = num[i-1];
                for(int j = i - 1; j < n-1; ++j){
                    num[j] = num[j+1];
                }
                return (char)(t+'0') + subPermutation(num, cnt, n - 1, k - (i-1)*cnt[n-1]);
            }
        }
        return "";
    }
};

Java实现。

public class Solution {
    public String getPermutation(int n, int k) {
        int [] fac = new int[n + 1];
        fac[0] = 1;
        int [] nums = new int[n + 1];
        for (int i = 1; i < fac.length; i++) {
			fac[i] = i * fac[i - 1];
			nums[i] = i;
		}
        
        int pos = 0;
        StringBuilder sb = new StringBuilder();
        for (int i = 1; i <= n; i++) {
        	int f = n - i;
			for (int j = 1; j <= n; j++) {
				if (j * fac[f] >= k) {
					pos = j;
					k -= (j - 1) * fac[f];
					break;
				}
			}
			for (int j = 1; j <= n; j++) {
				if (nums[j] > 0) {
					pos--;
				}
				if (pos == 0) {
					sb.append(nums[j]);
					nums[j] = -1;
					break;
				}
			}
			
		}
        return sb.toString();
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值