一、康托展开:全排列到一个自然数的双射
X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0!
ai为整数,并且0<=ai<i(1<=i<=n)
适用范围:没有重复元素的全排列
二、全排列的编码:
{1,2,3,4,...,n}的排列总共有n!种,将它们从小到大排序,怎样知道其中一种排列是有序序列中的第几个?
如 {1,2,3} 按从小到大排列一共6个:123 132 213 231 312 321。想知道321是{1,2,3}中第几个大的数。
这样考虑:第一位是3,小于3的数有1、2 。所以有2*2!个。再看小于第二位,小于2的数只有一个就是1 ,所以有1*1!=1 所以小于32
的{1,2,3}排列数有2*2!+1*1!=5个。所以321是第6个大的数。2*2!+1*1!是康托展开。(注意判断排列是第几个时要在康托展开的结果后+1)
再举个例子: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 5 7 4 1 2 9 6 8展开为98884,因为X=2*8!+3*7!+4*6!+2*5!+0*4!+0*3!+2*2!+0*1!+0*0!=98884.
解释:
排列的第一位是3,比3小的数有两个,以这样的数开始的排列有8!个,因此第一项为2*8!
排列的第二位是5,比5小的数有1、2、3、4,由于3已经出现,因此共有3个比5小的数,这样的排列有7!个,因此第二项为3*7!
以此类推,直至0*0!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#include<cstdio>
const
int
fac[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320};
int
KT(
int
s[],
int
n)
{
int
i, j, cnt, sum;
sum = 0;
for
(i = 0; i < n; ++i)
{
cnt = 0;
for
(j = i + 1; j < n; ++j)
if
(s[j] < s[i]) ++cnt;
sum += cnt * fac[n - i - 1];
}
return
sum;
}
int
main()
{
int
a[] = {3, 5, 7, 4, 1, 2, 9, 6, 8};
printf
(
"%d\n"
, 1 + KT(a,
sizeof
(a) /
sizeof
(*a)));
}
|
三、全排列的解码
如何找出第16个(按字典序的){1,2,3,4,5}的全排列?
1. 首先用16-1得到15
2. 用15去除4! 得到0余15
3. 用15去除3! 得到2余3
4. 用3去除2! 得到1余1
5. 用1去除1! 得到1余0
有0个数比它小的数是1,所以第一位是1
有2个数比它小的数是3,但1已经在之前出现过了所以是4
有1个数比它小的数是2,但1已经在之前出现过了所以是3
有1个数比它小的数是2,但1,3,4都出现过了所以是5
最后一个数只能是2
所以排列为1 4 3 5 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
#include<cstdio>
#include<cstring>
const
int
fac[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320};
bool
vis[10];
void
invKT(
int
ans[],
int
n,
int
k)
{
int
i, j, t;
memset
(vis, 0,
sizeof
(vis));
--k;
for
(i = 0; i < n; ++i)
{
t = k / fac[n - i - 1];
for
(j = 1; j <= n; j++)
if
(!vis[j])
{
if
(t == 0)
break
;
--t;
}
ans[i] = j, vis[j] =
true
;
k %= fac[n - i - 1];
}
}
int
main()
{
int
a[10];
invKT(a, 5, 16);
for
(
int
i = 0; i < 5; ++i)
printf
(
"%d "
, a[i]);
}
|
2.1.12 Next Permutation
描述
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).
e replacement must be in-place, do not allocate extra memory.
Here are some examples. Inputs are in the le-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
分析
算法过程如图2-1所示(来自http://fisherlei.blogspot.com/2012/12/leetcode-next-permutation.html)。
图2-1 下一个排列算法流程
代码
// LeetCode, Next Permutation
// 时间复杂度O(n),空间复杂度O(1)
class Solution {
public:
void nextPermutation(vector<int> &num) {
next_permutation(num.begin(), num.end());
}
template<typename BidiIt>
bool next_permutation(BidiIt first, BidiIt last) {
// Get a reversed range to simplify reversed traversal.
const auto rfirst = reverse_iterator<BidiIt>(last);
const auto rlast = reverse_iterator<BidiIt>(first);
// Begin from the second last element to the first element.
auto pivot = next(rfirst);
// Find `pivot`, which is the first element that is no less than its
// successor. `Prev` is used since `pivort` is a `reversed_iterator`.
while (pivot != rlast && *pivot >= *prev(pivot))
++pivot;
// No such elemenet found, current sequence is already the largest
// permutation, then rearrange to the first permutation and return false.
if (pivot == rlast) {
reverse(rfirst, rlast);
return false;
}
// Scan from right to left, find the first element that is greater than
// `pivot`.
auto change = find_if(rfirst, pivot, bind1st(less<int>(), *pivot));
swap(*change, *pivot);
reverse(rfirst, pivot);
return true;
}
};
相关题目
• Permutation Sequence, 见§2.1.13
• Permutations, 见§8.3
• Permutations II, 见§8.4
• Combinations, 见§8.5
2.1.13 Permutation Sequence
描述
e 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):
20 第2 章线性表
"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.
分析
简单的,可以用暴力枚举法,调用k