leetcode lcp 14切分数组

278 阅读1分钟
/**
 * @param {number[]} nums
 * @return {number}
 */
const PN = 10 ** 6 + 1
const PNSqrt = Math.sqrt(PN)
var splitArray = function(nums) {
    if((nums === null) || (nums.length === 0)) return 0
    const prime = []
    const isPrime = new Array(PN).fill(true)
    // 求出0 ~ 10 ** 6范围内的所有素数 
    for(let i = 2; i <= PNSqrt; i++) {
        if(!isPrime[i]) continue
        prime.push(i)
        for(let j = i; j < PN; j += i) isPrime[j] = false 
    }
    const n = nums.length
    const dp = new Array(n + 1).fill(n)
    const has = []
    const pFlag = new Array(PN).fill(n)
    dp[0] = 0
    for(let i = 1; i <= n; i++) {
        let x = nums[i - 1]
        has.length = 0
        for(let j = 0; j < prime.length; j++) {
            const p = prime[j]
            if(x < p) break
            if((x % p) === 0) {
                has.push(p)
                while((x % p) === 0) x /= p
            }
        }
        if(x !== 1) has.push(x)
        /**
         * 基本递推公式: 一个数都没遍历的时候, dp[0] = 0
         * 每遍历一个数x = nums[i], x要么跟[0, i -1]范围内的某个数组成一组, 要么
         * 自己单独一组, 具体怎么选择, 看怎么选择结果最小。
         * pFlag[p]记录的是在[0, i - 1]中, 我i遍历到i - 1为止,我前面的nums[i]有出现过质因数p, 我选择某一个位置t与i组成一组的情况下, dp[t - 1]的最小值。
         * 这里一个数的某个质因数如果是前面多个数的质因数, 那么应该选择使得结果最小的那个位置, 既不是最左的、也不是最右的
         * 
         */
        for(let j = 0; j < has.length; j++) {
            const p = has[j]
            pFlag[p] = Math.min(pFlag[p], dp[i - 1])
            dp[i] = Math.min(dp[i], pFlag[p] + 1)
        }
    }
    return dp[n]
};