leetcode-1175-质数排列

834 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

题目地址

请你帮忙给从 1 到 n 的数设计排列方案,使得所有的「质数」都应该被放在「质数索引」(索引从 1 开始)上;你需要返回可能的方案总数。

让我们一起来回顾一下「质数」:质数一定是大于 1 的,并且不能用两个小于它的正整数的乘积来表示。

由于答案可能会很大,所以请你返回答案 模 mod 10^9 + 7 之后的结果即可。

示例 1:

输入: n = 5
输出: 12
解释: 举个例子,[1,2,5,4,3] 是一个有效的排列,但 [5,2,3,4,1] 不是,因为在第二种情况里质数 5 被错误地放在索引为 1 的位置上。

示例 2:

输入: n = 100
输出: 682289015

提示:

  • 1 <= n <= 100

解题思路

本题题意稍微有一点绕,所以,首先我们来明确本题要我们做的是什么。
本题要求,所有的质数都只能放在质数索引上,所有的非质数只能放在非质数索引上,问从 1nn 个数字,共有多少种排列方式?
如果只考虑质数,因为索引和数字都是从 1n 的,我们只需要找出质数的数量,假设为 num,那么质数的排列方式总数就是 1~num 的阶乘,而非质数的排列方式的总数就是 1~n-num 的阶乘,总共的排列方式总数就是以上两个阶乘结果的乘积。
所以首先要求解的就是质数的数量,所谓质数,就是只能被 1 和其本身整除的整数,所以基于这个条件,我们可以遍历 2~n,求得质数的数量,然后就是分别不停计算乘积的过程了。
这里要注意的是因为 JavaScript 遵循 IEEE754 标准,所以最大安全整数为 253 次方减 1,而这里的乘积很可能会超过这个最大安全整数,所以要采用 BigInt 类型存储乘积。
如果不采用 BigInt 的话,还有两种方式可以准确计算出结果: 一种是对较大的数字拆成两部分,再分别进行乘法计算
还有一种是在更新质数数量和非质数数量的过程中同步计算结果,然后过程中对 1000000009 进行取余,这样就能保证计算过程中的结果尽可能小,不会超出最大安全整数。
对以上两种方法感兴趣的朋友可以去本题题解下查阅相关内容。

代码实现

function isPrimeNumber(num){
    for(let i = 2;i<num;i++){
        if(num%i===0){
            return false
        }
    }

    return true
}

var numPrimeArrangements = function(n) {
    let primeNum = 0
    
    for(let i = 2;i<=n;i++){
        if(isPrimeNumber(i)){
            primeNum++
        }
    }

    let res = BigInt(1)
    
    for(let i = 2;i<=primeNum;i++){
        res *= BigInt(i)
    }
    
    for(let i = 2;i<=n-primeNum;i++){
        res *= BigInt(i)
        res = res%BigInt(1000000007)
    }

    return res%BigInt(1000000007)
}

至此我们就完成了 leetcode-1175-质数排列

如有任何问题或建议,欢迎留言讨论!