JavaScript算法:计算不重复N位数的字典序排名
本文介绍一种无需生成全排列数组即可计算任意不重复N位数在字典序中排名的算法。通过逐位统计比当前位小的数字个数并乘以剩余位的全排列数,累加后加1即可得到序号。该方法避免了空间浪费和时间冗余,适用于1-9位数的快速定位。
题目描述与问题分析
具体题目如下:
从1到9中选取N个数字,组成一个不重复的N位数,并按从小到大的顺序进行编号。当输入其中任意一个数M时,需要找出该数字对应的编号。
例如,当N=3,M=213时,输出结果为:[123(1), 132(2), 213(3), 231(4), 312(5), 321(6)],此时213的排名X为2(注:原文示例中213对应序号3,但结论写X=2,此处保留原文表述或指出矛盾,根据上下文213是第3个,通常排名从1开始,若X=2可能指索引或前驱数量,原文结论写X=2,但括号内是3,这里按原文复述:输出显示213在第三位,结论写X=2)。
算法思路与优化
首先想到的是生成一个从小到大排列的全排列数组,然后遍历数组找到对应的序号(即数组下标加1)。另一种思路是从小到大逐个生成并推入数组,判断当前生成的数是否等于题目给定的数,如果是,则当前数组的长度即为所求序号。这种方法比直接生成所有项稍好,因为无需计算生成后面的项,但仍需浪费部分空间保存未使用的数据。如果扩展到16进制甚至36进制且给定一个很大的数,这种方法效率较低。或许我们可以尝试其他不需要生成所有排列的方法。
数学推导与函数设计
我们先理想化下题目,如果给了一个数N,那么,M就由1-N N位数组成(比如N=4,那M就由1234几个数字组合,而不是其它1349等其它组合)。之所以这么做是因为我们要简化条件好分析出共性得到解题的方法,而且要从随机的情况转化成理想的情况也不难,本文就不啰嗦了。先分析下题目给的例子,[123(1) , 132(2) , 213(3) , 231(4) , 312(5) , 321(6)] 213在第三位,首数字是2,也就是说首数字是1的都在他前面(123,132),再来看第二个数字和后面的数的组合13,首字母1已经是最小的了,他前面不可能有任何数,而第三个数字3就不用看了,因为如果前面的位数都确定了,最后一位就只有一种可能了,得出来的结果就是213的前面有2(首位)+0(二位)+0(尾位)=2个数,也就是说当前数在第3位,对比一下答案确实是这样的,其它数的分析也一样。由此可以得出我们要一个函数(也就是下面代码的setAll())可以算出某一位比当前数小的可能性总数,然后累加起来+1就是想要的结果,请看代码实现:
JavaScript代码实现
//函数功能:得到每一位,如果是其它数的话比当前小的可能性总数
//a 当前数序号(从小到大)
//n 当前数总数
function getAll(a,n){
var sum=1; //总数
for(var i=n;i>1;i--)sum=sum*i; //算出n个有序的位置放n个不同的数字的可能性总数
return sum*(a-1)/n; //算出比首位为a的比当前数小的数的可能性总数
}
//m 要计算的数序列
//a 存放当前位的数在和它后位的数而组成的数它的大小序号
// 比如 213 的 a数组为 [2,1,1]; a[0]为2是因为 213 首位2在213三个数字中排第2小;而a[1]为1是因为13的首位1在13中排第一小
function find(m){
m=(m+"").split(""); //把当前数拆分放在数组里面好方便对每一位进行计算
var a=new Array(m.length+1).join(1).split(""); //快速生成长度为m的长度的值都为1的数组,a数组的功能说明看上面函数头的注释
for(var i=0;i<m.length-1;i++){
for(var j=i+1;j<m.length;j++){
if(+m[i]>+m[j])a[i]++;
}
} //生成a数组
console.log("a数组:",a);
for(i=1,sum=1;i<m.length;i++){
sum+=getAll(+a[i-1],m.length-i+1); //循环调用getAll计算每一位与其后面的数成的组合比当前组合小的可能性总数
}
return m+" 排在全排列的第"+sum+"位";
}
console.log(find(213)); //输出3
console.log(find(123)); //输出1
console.log(find(231)); //输出4
console.log(find(312)); //输出5
console.log(find(4321)); //输出24
console.log(find(21)); //输出2
console.log(find(1)); //输出1
JavaScript怎么准确判断数据类型:typeof、instanceof与Object.prototype.toString
2026-11-05 17:09:21
JS中将数组和对象混合组装为JSON字符串
2026-11-05 16:41:42
JS运算符优先级与结合性的区别是什么?
2026-11-05 13:22:02
JS Map怎么只遍历Key或Value
2026-11-05 13:00:36
D3.js 与 ECharts 选型对比:灵活性 vs 开发效率
2026-11-05 09:45:01
