逻辑题目,给定26!字母排列(有规律),给 任意数字 求出 排列的结果?

假如有abc,共有3!的排列结果,
排列顺序是 abc acb bac bca cab cba
给任意数字,比如N=4,就要输出bca。

现在有26英文字母,共26!种排列方式,给任意数字N,该如何求出字母列?

听别人说用递归就可以解决,但实在想不出什么解法

阅读 4.4k
4 个回答
//共有 count 种排列方式
var counts = Object.create(null)
function getCount(len){
    if(!counts[len]){
        var count = 1;
        while(len > 1){
            count *= len
            len--
        }
        counts[len] = count
    }
    return counts[len]
}

var getStr = function(arr){
    //if(!Array.isArray(arr))return;
    if(Object.prototype.toString.call(arr) !== "[object Array]")return;
    
    var len = arr.length
    
    return function(n){
        if(n < 1){
            alert('数值超出下限,错误')
            return false
        }
        if(n > getCount(len = arr.length)){
            alert('数值超出上限,错误')
            return false
        }
        n -= 1;//在计数中下标从0开始
        
        var index = 0,
            newArr = arr.slice(),
            resulte = [],
            count = 0
        
        //一位一位的获取元素
        while(len > 1){
            //获取改长度下的可能组合数
            count = getCount(len)
            //用n的值算出剩余元素首位元素在数组中的位置
            //比如5位的数组可能组合有120种,那么第110个(下标0开始)的组合的首位元素就是
            // 110*5/120 | 0 = 4,下标4,也就是e
            index = n*len/count | 0
            //从数组中删除这个元素,并追加到结果集合中
            resulte.push(newArr.splice(index,1))
            //从第一种组合到下标为4的元素排第一的组合数占去了 4*120/5 个
            // 那么相对剩余几个元素组合数的位置就变成了
            // n = 110 - 4*120/5 = 14
            n -= index*count/len
            len--
        }
        //追加最后一个元素
        len == 1 && resulte.push(newArr[0])
        
        console.log(resulte.join(''))
    }
}(['a','b','c','d','e'])

getStr(1); // 'abcde'
getStr(4); // 'abdec'
getStr(120); // 'edcba'
getStr(119); // 'edcab'

递归是能解决,这么说吧,递归的思想就是将大问题化作小问题,那么这个问题怎么来划分呢?就以 abcd 为例子看一下。

因为排列结果共有 4!种,并且由于是顺序,那么:

  • 第一位就有 4 种可能,剩余三位共有 3! 种
  • 第二位就有 3 种可能,剩余两位共有 2! 种
  • 第三位就有 2 种可能,剩余一位共有 1! 种

所以,假设 N = 9,那么根据上面的过程,第一位如果是 a,那么其余位共有 3! 种可能,由于 3! < 9,那么第一位必然不是 a,所以要递增一位,改为 b,加上之前 a 的组合数,3!+ 3!> 9,所以无论最后的排列是什么,这个排列的第一位肯定是 b,之后问题求解规模就缩小了,相当于在 acd 三个字母中的,求当 N = 3 的排列结果,直到你找到所有位的字母(也就是 N = 0 的时候)。

转化的过程大概是这样的(*代表未知字母):

  • s = xxxx, N = 9
  • s = bxxx, N = 3
  • s = bcxx, N = 1
  • s = bcad, N = 0

如有错误,还望指正,大神轻喷

有意思,一看题目我想到的就是先把排列全部算一遍组成一个数组,然后任意数字N直接从这个数组里面索引出来就是结果了。
我目前的思路是如果规律固定即abc acb bac bca cab cba的话,把26个字母拆分成数组,每个位的字母在相应数字下应该有个算法可以得出位移目标,但是具体算法还得抽空想想,实现了再追答


hfhan 已经给出实现算法,很赞

https://blog.csdn.net/u010271...
这个例子中的result就是最后放结果的数组,顺序有问题的话,直接调用一下sort()方法,就是按照字母顺序排列的数组了。
然后index访问result数组就是想要的结果。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题