[路飞]_前端算法第三十二弹-面试题 17.09. 第 k 个数

154 阅读2分钟

「这是我参与11月更文挑战的第21天,活动详情查看:2021最后一次更文挑战

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

示例 1:

输入: k = 5
输出: 9

动态规划+指针+小根堆

这道题用到了动态规划,指针和小根堆的思想,我们要找出所有只包含3,5,7素因子的数,而且需要从小到大排列,所以我们需要算出,每一步的最小值,因为只包含3,5,7所以后面的数必定都从这三个数中得来,也必定是与这三个数多次相乘的结果,所以我们在计算下一个数时,则需要从前面的数中,找到合适的数与这三个数相乘,来得到下一个最小的数,这便用到了动态规划的思想,同时我们需要三个指针分别指向3,5,7,用之前计算所得的数乘以他们从而得到新的最小值,当此时2,5,7与当前值计算过之后则需要将该指针指向下一个数字,这样避免重复计算,再将三个数计算的结果进行比较取最小值。

  • 生成一个长度为K+1,元素都为1的数组,
  • 从下标为2开始,填充计算所得数
  • 将p3,p5,p7都指向下下标为1的数,与之相乘找到乘积最小的指针
  • 记录最小的指针数到数组中,并将该指针+1
  • 判断其余指针有没有乘积相同的情况,如果有,指针+1

其实就是从下标为2时,开始填充,从下标为1时开始计算,三个指针都指向下标为1的数,也就是1,取出最小值,为3,即dp[p3]3=1,此时dp[2]=3,而31已经计算过了,所以p3++,代表,下次计算时,3不和1相乘,和下一个最小数3相乘作比较。

var getKthMagicNumber = function (k) {
    let dp = new Array(k + 1).fill(1)
    let p3 = 1, p5 = 1, p7 = 1;
    for (let i = 2; i <= k; i++) {
        dp[i] = Math.min(dp[p3] * 3, dp[p5] * 5, dp[p7] * 7)
        if (dp[i] == dp[p3] * 3) p3++
        if (dp[i] == dp[p5] * 5) p5++
        if (dp[i] == dp[p7] * 7) p7++
    }
    return dp[k]
};