一日一练:第k个数

110 阅读1分钟

有些数的素因子只有 3,5,7,请设计一个算法找出第 k 个数。注意,不是必须有这些素因子,而是必须不包含其他的素因子。例如,前几个数按顺序应该是 1,3,5,7,9,15,21。

为什么朴素算法不好用?

最初拿到题目,可能会想到用[3, 5, 7]逐个去与[1]相乘,结果放入后面的数组中,得到[1, 3, 5, 7],然后继续用[3, 5, 7]与第二个数相乘。。。如下图

image.png

当算到第三组的时候,就会发现有两个问题:

    1. 可能存在重复数值的情况,3 * 55 * 3的结果重复了
    1. 第二轮计算中的结果3 * 7大于第三轮计算中的结果5 * 3

这两个问题都对结果数组中的顺序产品影响。这两个问题都告诉我们,这道题用暴力的扫描(朴素算法)是行不通的。

这里的第一个问题,是否可以去重,可以,但是每次结果都得扫描之前的所有数据。

是否可以保证后面的计算值都大于前面的值,或者说是否每次都能找到最小的值?可以。那么就变成典型的最优解的问题。

解题思路: 三指针 + 步进

image.png

然后代码为:

function getKthMagicNumber(k: number): number {
    // 初始数据存在元素 1
    const dp: number[] = [1]
    let p1 = 0, p2 = 0, p3 = 0
    let v1,v2,v3
    let count = k
    // 第k个,即索引为 k-1
    while(--count) {                
        // 获取最小值
        let min = Math.min((v1 = dp[p1] * 3), (v2 = dp[p2] * 5), (v3 = dp[p3] * 7))
        dp.push(min)
        // 根据最小值,获得需要步进的指针
        if (min === v1) p1++
        if (min === v2) p2++
        if (min === v3) p3++
    }
    return dp[k - 1]
};