排列序号
题目
给出一个不含重复数字的排列,求这些数字的所有排列按字典序排序后该排列的编号。其中,编号从1开始。
样例
例如,排列 [1,2,4] 是第 1 个排列。
题解
由于本题不需要计算出所有排列,则可用排列组合的原理直接解出答案。举个例子, [2,3,1,4]共有4!种排列方法,答案要求是从[1,2,3,4]按字典排序至[2,3,1,4]有多少种排法。在每确定一位的情况下剩余的所有排法为(n-i)!,即在第1位2确定的情况下有3!种排法,在前两位都确定的情况下有2!种排法…
由于字典排序是从小到大排列的,所以只需计算出第i位(从1开始)在它后面比它小的数的个数m,再用m*(n-i)!,遍历计算即可。
public class Solution {
/**
* @param A an integer array
* @return a long integer
*/
public long permutationIndex(int[] A) {
int count = 0;
long index = 0;
long weight = 1;
for (int i = A.length - 2;i>=0; i--)
{
count = 0;
weight *= A.length - i - 1;
for (int j=i+1;j<A.length;j++)
{
if (A[i] > A[j])
{
count++;
}
}
index += count * weight;
}
return ++index;
}
}
2.字典排序解法
也是最笨的解法,由全部排法(n!)减去目前数组的后续排法就是答案。由于该方法在LC中会超时,所以只供参考。
public class Solution {
/**
* @param A an integer array
* @return a long integer
*/
public long permutationIndex(int[] A) {
int count = 0;
while (nextPermutation(A))
{
count++;
}
int sum = 1;
int n = A.length;
while (n>0)
{
sum *= n;
n--;
}
return sum - count;
}
private boolean nextPermutation(int[] arr)
{
int i=arr.length-2;
boolean bFind = false;
for(;i >= 0;i--)
{
if(arr[i] < arr[i + 1])
{
bFind = true;
break;
}
}
if (!bFind)
{
return false;
}
int j = i;
for (int k=i+1;k<arr.length;k++)
{
if (arr[k] >= arr[i])
{
j = k;
}
}
swap(arr, i, j);
reverse(arr, i+1, arr.length-1);
return true;
}
private void swap(int[] arr, int a, int b)
{
int t = arr[a];
arr[a] = arr[b];
arr[b] = t;
}
private void reverse(int[] arr,int start, int end)
{
while (start < end)
{
swap(arr, start++, end--);
}
}
}
Last Update 2016.9.13