问题:生成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);
}