LeetCode算法题目:Permutations

题目:

Given a collection of distinct numbers, return all possible permutations.
For example,
[1,2,3] have the following permutations:

[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]


分析:


  1. 方法一:可以一个一个的按次序求排列。使用Next Permutation方法

使用Next Permutation方法按次序依次求出序列。
详见http://blog.csdn.net/qq_24835809/article/details/71440349

  • 方法二:采用数学解法:Cantor expansion(康托编码)
  • Cantor expansion算法的思想是,在n!个排列中,第一位的元素总是(n-1)!一组出现的,也就说如果p = k / (n-1)!,那么排列的最开始一个元素一定是nums[p]。以下公式给出了全排列到一个自然数的一一双射:

    X=an(n-1)!+an-1(n-2)!+…+ai*(i-1)!+…+a2*1!+a1*0!

    举个例子:

    问1324是{1,2,3,4}排列数中第几个组合:
    第一位是1,小于1的数没有,是0个,0*3!,第二位是3,小于3的数有1和2,但1已经存在于第一位了,所以只有一个数2,1*2! 。第三位是2小于2的数是1,但1在第一位,所以有0个数,0*1!,所以比1324小的排列有0*3!+1*2!+0*1!=2个,1324是第3个组合。
    以上是Cantor编码的过程,即把一个全排列映射1324为一个自然数3,而该题目是已知一个自然数k,求其对应的全排列,相对以上步骤来说是一个解码的过程,下面给出一个具体的例子:
    如何找出{1,2,3,4,5}的第16个排列?
    1. 首先用16-1,得到15;
    2. 用15去除4! ,得到0,余15;
    3. 用15去除3! ,得到2,余3;
    4. 用3去除2! ,得到1,余1;
    5. 用1去除1! ,得到1,余0;
    6. 有0个数比它小的数是1,所以第一位是1;
    7. 有2个数比它小的数是3,但1已经在之前出现过,所以第二位是4;
    8. 有1个数比它小的数是2,但1已经在之前出现过了所以第三位是3;
    9. 有1个数比它小的数是2,但1,3,4都出现过了所以第四位是5;
    10. 根据上述推论,最后一个数只能是2;
    所以排列为{1,4,3,5,2}。


代码:

方法一:

class Solution {
public:
    vector<vector<int> > permute(vector<int> &num) {
        vector<vector<int> > result;
        sort(num.begin(),num.end());
        do{
            result.push_back(num);
        }while(next_permutation(num.begin(),num.end()));
        return result;
    }
};

方法二:

class Solution {
public:
    vector<vector<int> > permute(vector<int> &num) {
        int length=num.size();
        int k=fac(length);
        vector<vector<int>> result;
        sort(num.begin(),num.end());
        for(int i=0;i < k; i++){
            vector<int> visited(num);
            vector<int> temp;
            int p=i;
            for(int j = length-1;j > 0;j --){
                int m=p/fac(j);
                temp.push_back(visited[m]);
                visited.erase(visited.begin()+m);
                p%=fac(j);
            }
            temp.push_back(visited[0]);
            result.push_back(temp);
        }
        return result;
    }
private:
    int fac(int n){
        int num = 1;
        for (int i = 1; i < n + 1; ++i)
            num *= i;
        return num;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值