197-排列序号
给出一个不含重复数字的排列,求这些数字的所有排列按字典序排序后该排列的编号。其中,编号从1开始。
样例
例如,排列 [1,2,4] 是第 1 个排列。
思路
参考http://www.cnblogs.com/hujunzheng/p/5020211.html
首先观察一个全排列, 例如:95412 = X
- 题目转换成按照字典序,这个全排列之前有多少个全排列。
- X的前面的所有全排列中,对于位置1上可以是5, 4, 1, 2任意一个数,而且对应的全排列的基数都是4!个。
- 同理位置2, 3, 4, 5对应的基数分别是,3!,2!,1!,0!(0!==0)。
- 得到该位置对应的基数后,那么该位置对应多少个可变数字?9所在位置对应的可变数字的个数为4,分别是5,4,1,2;5所在位置对应的可变数字是4,1,2;4所在位置对应的可变数字是1,2,;1所在位置的对应的可变数字:无。2所在位置对应可变数也是无。
- 可以得到结论,X全排列某个位置上对应的可变数字的个数 == 这个数后面有多少个比它小的数的个数。
- 为了得到某个数后面有多少个比它小的数的个数,我们采用折半插入排序(从后向前插入)。
首先计算每一位 A[i] 的后面小于它的数的个数 count,而 i 后面又应该有 n-i-1 位,就有 (n-1-i)! 种排列的可能,所以在 A[i] 之前的可能排列就有 count * (n-1-i)! 个。
所以遍历数组,所有元素的 count * (n-1-i)! 之和再加 1 就是当前排列的序号
code
class Solution {
public:
/**
* @param A an integer array
* @return a long integer
*/
long long permutationIndex(vector<int>& A) {
// Write your code here
int size = A.size();
if (size <= 0) {
return 0;
}
long long result = 1, fac = 1, base = 1;
for (int i = size - 1; i >= 0; i--) {
int count = 0;
for (int j = i + 1; j < size; j++) {
if (A[j] < A[i]) {
count++;
}
}
result += count * fac;
fac *= (size - i);
}
return result;
}
};