有些数的素因子只有 3,5,7,请设计一个算法找出第 k 个数。注意,不是必须有这些素因子,而是必须不包含其他的素因子。例如,前几个数按顺序应该是 1,3,5,7,9,15,21。
为什么朴素算法不好用?
最初拿到题目,可能会想到用[3, 5, 7]逐个去与[1]相乘,结果放入后面的数组中,得到[1, 3, 5, 7],然后继续用[3, 5, 7]与第二个数相乘。。。如下图
当算到第三组的时候,就会发现有两个问题:
-
- 可能存在重复数值的情况,
3 * 5与5 * 3的结果重复了
- 可能存在重复数值的情况,
-
- 第二轮计算中的结果
3 * 7大于第三轮计算中的结果5 * 3
- 第二轮计算中的结果
这两个问题都对结果数组中的顺序产品影响。这两个问题都告诉我们,这道题用暴力的扫描(朴素算法)是行不通的。
这里的第一个问题,是否可以去重,可以,但是每次结果都得扫描之前的所有数据。
是否可以保证后面的计算值都大于前面的值,或者说是否每次都能找到最小的值?可以。那么就变成典型的最优解的问题。
解题思路: 三指针 + 步进
然后代码为:
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]
};