题目描述
现在有"abcdefghijkl”12个字符,将其所有的排列中按字典序排列,给出任意一种排列,说出这个排列在所有的排列中是第几小的?
输入
第一行有一个整数n(0<n<=10000); 随后有n行,每行是一个排列;
| 样例输入
3 abcdefghijkl hgebkflacdji gfkedhjblcia
|
输出
输出一个整数m,占一行,m表示排列是第几位;
| 样例输出
1 302715242 260726926 |
解题思路:首先说一下我当时的解题思路吧,这个题目很自然的想到要用到排列的知识来解决。于是我设立一个排序好的原数组,也就是刚开始题目给出的。两次循环,外层循环是遍历样例的每个字符,内层循环则是判断他是第几小(也就是它在剩下的元素中的坐标)。我每次找到元素后,就用‘@’替换原来的元素。找出第几小之后做一个累乘。结果:只能通过一个样例(‘abcdefghijk’)。想了很久,一直想不出来自己哪里错了,就从网上百度了一下。
原来这个题目需要用到康托展开,这么一个数学排列公式。康托展开是一个全排列到一个自然数的双射,常用于构建hash表时的空间压缩。设有n个数(1,2,3,4,…,n),可以有组成不同(n!种)的排列组合,康托展开表示的就是是当前排列组合在n个不同元素的全排列中的名次。
大佬博客:https://blog.csdn.net/wbin233/article/details/72998375上面讲的比较清楚。另外还发现了另外一名大佬的博客,讲的也不错:https://www.cnblogs.com/wsss/p/5473487.html
代码:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
public class Main {
public static long fac(int n){
if(n==0||n==1)
return 1;
else
return n*fac(n-1);
}
public static void main(String[] args) throws ParseException {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
String line = sc.nextLine();
for(int i=0;i<N;i++){
String s = sc.nextLine();
char tmp[]=s.toCharArray();
long sum = 1;
for(int j=0;j<12;j++){
int count = 0;
for(int k=j+1;k<12;k++){
if (tmp[j]>tmp[k])
count++;
}
sum+=count*fac(11-j);
}
System.out.println(sum);
}
}
}