一. 全排列递归算法
1. 数据没有重复的情况下
算法:每个元素依次与后面的数进行交换
例子:假设元素为123,则递归交换事例如下:
2. 数据有重复的情况下、
算法:在没有数据重复的全排列下,交换需要加上前提条件,即元素应该和后面没有重复出现的数字进行交换,即当访问到第k个元素的时候,如果 [k, j)中,没有元素与num[j]相等,则可以交换num[k],num[j]
二. 全排列的迭代算法
参照STL中的实现,算法如下:
1. 在序列中,从后往前寻找第一对递增的元素对,前面一个数为替换数,位置为替换点
2. 接着依然从后往前寻找第一个大于替换数的元素(一定可以找到),记为A
3. 交换替换数与A,然后反转替换点后面的序列
4. 步骤1中如果没有找到,直接反转整个序列
leetcode 中 Permutation Sequence,
Permutations II
,Next Permutation均使用上面的算法,代码如下:
class Solution {
public:
//没有重复的情况
vector<vector<int> > permute(vector<int> &num) {
ans.clear();
allrange(num, 0, num.size());
return ans;
}
void allrange(vector<int>& num, int k, int n) {
if( k == n ) ans.push_back(num); //扫完最后一个元素的时候,num数组就是一个全排列
for(int i=k; i<n; ++i) { //从k开始,第k个数依次与后面的数进行交换
swap(num[k], num[i]);
allrange(num, k+1, n); //交换完,开始进行后面部分的全排列
swap(num[k], num[i]);
}
}
//有重复的情况
vector<vector<int> > permuteUnique(vector<int> &num) {
ans.clear();
allrange2(num, 0, num.size());
return ans;
}
//在[ibegin,iend)中寻找是否有=num[iend]的元素,有则不交换,没有就交换
bool isNeedSwap(vector<int>& num, int ibegin, int iend) {
for(int i=ibegin; i<iend; ++i)
if( num[i] == num[iend] ) return false;
return true;
}
void allrange2(vector<int>& num, int k, int n) {
if( k == n ) ans.push_back(num); //扫完最后一个元素,num数组就是一个全排列
for(int i=k; i<n; ++i) //从k开始,第k个数依次与后面的数进行交换
if( isNeedSwap(num, k, i) ) { //若没有重复,则交换
swap(num[k], num[i]);
allrange2(num, k+1, n); //交换完,开始进行后面部分的全排列
swap(num[k], num[i]);
}
}
//求下一个全排列
void nextPermutation(vector<int> &num) {
vector<int>::iterator cur = num.end();
vector<int>::iterator pre = cur-1;
while( pre != num.begin() ) {
--pre; //指向cur前面一个元素
--cur;
if( *pre < *cur ) { //第一对递增的元素,pre为替换点,*pre为替换数
cur = --num.end();
while( *pre >= *cur ) --cur; //从后往前寻找第一个大于*pre的元素,并与*pre交换
swap( *pre, *cur );
reverse(pre+1, num.end()); //反转替换点之后的元素
return ;
}
}
reverse(num.begin(), num.end()); //数列已是“最后”的序列是,则直接反转
return ;
}
private:
vector< vector<int> > ans;
};
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):
"123"
"132"
"213"
"231"
"312"
"321"
Given n and k, return the kth permutation sequence.
Note: Given n will be between 1 and 9 inclusive.
假设数列有3个元素 1 2 3,求第4个序列,则有:
序号 排列
1 123
2 132
3 213
4 231
5 312
6 321
3个元素的时候,则1开头,23的全排有2!= 2种,2开头,13全排有2种,3开头,12全排有2种。
由于要求第4个序列,则会发现 2 < 4 <= 4,这时第1位选择2。
此时元素剩下13,k更新为4-2=2,即在13的全排中求第2个序列。那么1开头,3的全排只有1种,3开头,1的全排只有1种,即序号为
序号 排列
1 13
2 31
由于求第2个序列,则会发现 1 < 2 <= 2,这时第2位选择3,最后元素只剩下1了,那么所求即为231
代码如下:
class Solution {
public:
string getPermutation(int n, int k) {
string str = string("123456789").substr(0, n); //取前n个数字
string ans;
for(int i=0; i<n; ++i) k = getKth(ans, str, k); //每次获取第i个数
return ans;
}
int getKth(string& ans, string& str, int k) {
int num = fac(str.size()-1); //求(str.size()-1)!
int idx = (k-1) / num; //这位应选取的数是str[idx],注意下标是从0开始
ans.push_back(str[idx]); //放入ans中
str.erase(idx, 1); //原数列删除str[idx]
return k - idx * num; //返回新k值
}
int fac(int n) { //求n的阶乘
int ans = 1;
for(int i=2; i<=n; ++i) ans *= i;
return ans;
}
};