全排列生成算法

问题:生成1~n的全排列(生成一个数组中所有元素的全排列)。

方法一:字典序方法

思想:依据字典序顺序,由前一个排列,生成后一个排列。
代码:

//字典序方法:输入前一个排列,输出后一个排列
vector<int> &nextPermutation(vector<int> &p){
    unsigned long left,right;

    left=right=p.size()-1;
    while(left-1>=0 && p[left-1]>=p[left]) left--;
    left--;

    while(p[right]<=p[left]) right--;
    swap(p[left],p[right]);

    for(int i=left+1,j=p.size()-1;i<j;i++,j--){
        swap(p[i],p[j]);
    }
    return p;
}

//主调用方法
void generatePermutation(int n){
    vector<int> p(n,0);
    int totalCount=1;
    for(int i=0;i<n;i++){
        p[i] = i+1;
        totalCount *= i+1;
    }

    for(int i=0;i<totalCount;i++){
        cout << i+1 << ":";
        print(p); //打印数组
        p=nextPermutation(p);
    }

}

方法二:递归交换方法

思想:问题分解,n个元素的全排列,可以分解为:
- 1.最左边的位置(n钟情况);和
- 2.右边n-1个元素的全排列。

代码:

//递归方法,问题分解为其子问题,每次交换首元素和剩下元素中某一个的位置
void recursionGenerate(vector<int> &p,int begin,int end){
    if(begin>=end){
        print(p);
        return ;
    }
    for(int i=begin;i<=end;i++){ //最左边的位置有n种情况
        swap(p[begin],p[i]);
        recursionGenerate(p, begin+1, end); //递归调用
        swap(p[begin],p[i]);
    }
}
//主调用方法
void generatePermutation2(int n){
    vector<int> p(n,0);
    for(int i=0;i<n;i++){
        p[i]=i+1;
    }
    recursionGenerate(p, 0, n-1);
}

方法三:由(全排列)序号生成排列

//对应序号的排列,输入:排列的序号,输出:排列
vector<int> &num2perm(int n,int num){
    static vector<int> ret;
    vector<int> candidate(n,0);
    int k=1,index;
    for(int i=0;i<n;i++){
        candidate[i]=i+1;   //candidate={1,2,...,n}
        k*=i+1;             //k=n!
    }
    ret.clear();
    for(int i=0;i<n;i++){
        k/=n-i;
        index = (num-1)/k;      //num-1 -> candidate[index]
        num-=index*k;           //num-=index*k;
        ret.push_back(candidate[index]);
        candidate.erase(candidate.begin()+index);
    }
    return ret;
}
//主调用函数
void generatePermutation3(int n){
    int num=1;
    for(int i=0;i<n;i++){
        num*=i+1;
    }
    for(int i=1;i<=num;i++){
        print(num2perm(n, i));
    }

}

打印数组函数

void print(const vector<int> &v){
    for(int i=0;i<v.size();i++){
        cout << v[i] << " ";
    }
    cout << endl;
}

问题扩展

问题:如果在上面问题的基础上,增加了“数组元素可能重复”的条件。

解法:如果用交换法来解,需要定义一个set来存储已经交换过的元素值。

代码:

//递归方法,问题分解为其子问题,每次交换首元素和剩下元素中某一个的位置
void recursionGenerate(vector<int> &p,int begin,int end){
    if(begin>=end){
        print(p);
        return ;
    }
    set<int> swap_set;
    for(int i=begin;i<=end;i++){
        if(swap_set.find(p[i])!=swap_set.end())
            continue;
        swap_set.insert(p[i]);
        swap(p[begin],p[i]);
        recursionGenerate(p, begin+1, end);
        swap(p[begin],p[i]);
    }
}

void generatePermutation2(vector<int> &p){
    recursionGenerate(p, 0, p.size()-1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值