关于permutation的讲解,请参见http://blog.csdn.net/xuqingict/article/details/24840183
[updated 2014.7.30]
所有的Permutation无论是否有重复元素,直接使用下面的代码即可,
bool helper(vector &num)
{
if(num.empty()) return false;
typedef vector::iterator iter;
iter first=num.begin(), last=num.end();
--last;
if(first==last) return false;
while(last != first && !(*(last-1) < *last))--last; //此处直接使用!< 即可。。。
if(last==first) return false;
iter left=last-1,right=last;
last=num.end();
--last;
while(!(*left < *last))--last; //同上!!!
iter_swap(left,last);
reverse(right,num.end());
return true;
}
public:
vector > permuteUnique(vector &num) {
if(num.empty()) return vector >();
vector > ret;
sort(num.begin(), num.end());
do
{
ret.push_back(num);
}while(helper(num));
return ret;
}
下列题目的讲解均是基于上面的文章:
题1:
Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.
If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).
The replacement must be in-place, do not allocate extra memory.
Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.1,2,3
→ 1,3,2
3,2,1
→ 1,2,3
1,1,5
→ 1,5,1
给定一个permutation,直接求出下一个:
class Solution {
public:
void nextPermutation(vector &num) {
typedef vector::iterator iter;
iter beg = num.begin(), end = num.end();
if( beg == end || beg + 1 == end)return;
iter right = end;
--right;
for(;;)
{
iter left = right;
--left;
if(*left < *right)
{
iter k = end;
while(!(*left < *--k)){}
iter_swap(left, k);
reverse(right,end);
return;
}
--right;
if(right == beg)
{
reverse(beg, end);
return;
}
}
}
};
Given a collection of 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]
, and [3,2,1]
.
class Solution {
private:
typedef vector::iterator iter;
bool helper(iter first, iter last)
{
if(first == last) return false;
if(first + 1 == last) return false;
iter j = last;
--j;
while(1)
{
iter i = j;
--i;
//find a[i] < a[j] and they are adjacent
if(*i < *j)
{
iter k = last;
while(!(*i < *--k)){}
std::swap(*i,*k);
std::reverse(j,last);
return true;
}
--j;
//no such a[i] < a[i+1] pair found
if( j == first)
{
//restore the first of the permutation
std::reverse(first, last);
return false;
}
}
}
public:
vector > permute(vector &num) {
vector > ret;
if(num.empty())return ret;
iter beg = num.begin(), end = num.end();
if(beg + 1 == end)
{
ret.push_back(num);
return ret;
}
sort(beg,end); //首先必须sort!!!!
do{
ret.push_back(num);
}while(helper(beg, end));
return ret;
}
};
题3:
Given a collection of numbers that might contain duplicates, return all possible unique permutations.
For example,[1,1,2]
have the following unique permutations:[1,1,2]
, [1,2,1]
, and [2,1,1]
.
class Solution {
private:
typedef vector::iterator iter;
bool permutation(iter beg, iter end)
{
if(beg == end || beg + 1 == end)
{
return false;
}
iter right = end;
--right;
while(1)
{
iter left = right;
--left;
if(*left < *right)
{
iter k = end;
while(!(*left < *--k)){}
iter_swap(left,k);
reverse(right,end);
return true;
}
--right;
if(right == beg)
{
reverse(beg,end);
return false;
}
}
}
public:
vector > permuteUnique(vector &num) {
set > unique;
sort(num.begin(), num.end());
do
{
if(unique.count(num) == 0 )
unique.insert(num);
}while(permutation(num.begin(),num.end()));
vector > ret(unique.begin(), unique.end());
/*for(set >::iterator it = unique.begin();
it != unique.end() ; ++it)
{
ret.push_back(*it);
}*/
return ret;
}
};
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.
解题思路:
首先,假设 n = 3, k = 4 , 我们可以得到上述的编码,可以发现,前 (n-1)!个元素是以 1 开头的,,第二组 (n-1)!的元素是以2开头的,那么我们就可以有
k = 4 = 2*2! + 0* 1! + 0*0!,那么该串中的字符应该是第2个,第0个,以及第0个字符,这里请注意,每一步的原始的元素集合是在减少1 的,比如;
第2个意味着 “123”的第2个,为‘3’, 那么此时的串变为 “12”
第0个意味着 “12”的第0个, 为 ‘1’,那么此时的串变为 “2”
第0个意味着 “2”的第0个,为 ‘2’, 那么此时串为空,结束,那么结果即为 “312”。
但是我们发现现在求的 “312”实际上是第5个(因为结果是从1开始的),因此只需要在计算之前将 k减一即可。也就是说在k之前一共有 k-1 个permutation,因此代码为:
class Solution {
public:
string getPermutation(int n, int k)
{
string str;
for(int i = 1 ; i <= n ; ++i)
str += ('0' + i);
string ret;
int base = 1;
for(int i = n-1 ; i >= 1 ; --i)
{
base *= i;
}
--k;
int i = n-1;
while(i > 0 && k > 0) // iterate (n-1) times
{
int pos = k/base;
k = k % base;
ret += str[pos];
str.erase(pos,1);
base /= i;
--i;
}
//[updated] 可以直接写成if(!str.empty()) ret+=str;
while(!str.empty())
{
ret += str[0];
str.erase(0,1);
--i;
}
return ret;
}
};