leetcode 面试题 17.09. 第 k 个数

173 阅读3分钟

这是我参与2022首次更文挑战的第21天,活动详情查看:2022首次更文挑战

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

示例 1:

输入: k = 5

输出: 9

注意,不是必须有这些素因子,而是必须不包含其他的素因子。例如,前几个数按顺序应该是 1,3,5,7,9,15,21。

隐藏提示1

明确这个问题的要求。要求满足 3a× 5b× 7c 这一形式的第 k 小的值。

隐藏提示2

蛮力解法得到的形如 3a× 5b × 7c 的第 k 小的值是什么样的?

隐藏提示3

在寻找 3a × 5b × 7c 的第 k 个最小值时,我们知道 a、b、c 将小于等于 k。你能生成所有可能的数字吗?

隐藏提示4

查看 3a×5b×7c 对应的所有值的列表,可以观察到列表中的每个值都是 3×(列表中前面的某值)、5×(列表中前面的某值)或 7×(列表中前面的某值)。

隐藏提示5

由于每个数字都是列表中先前值的 3 倍、5 倍或 7 倍,因此我们可以检查所有可能的值,然后选择下一个还没有看到的值。这将导致许多重复的工作。如何才能避免这种情况呢?

隐藏提示6

不要检查列表中的所有值来寻找下一个值(通过将每个值乘以 3、5、7),而是这样考虑:当你将一个值 x 插入列表时,可以“构造”3x、5x 和 7x 以供以后使用。

隐藏提示7

当你将 x 添加到前 k 个值的列表中时,可以将 3x、5x 和 7x 添加到新的列表中。如何使其尽可能地优化?保留多个队列如何?总是需要插入 3x、5x 和 7x 吗? 或者,有时你只需要插入 7x?你需要避免相同的数字出现两次。

看完这个写提示看感觉这个题是人说的话嘛?根本不是,经过大量数据的测试发现算的是他们幂运算

当i = 0; idx1 = idx2 = idx3 = 0 时,3的0次幂 X 5的0次幂 * 7的0次幂 = 1

当i = 1; idx1 = 1, idx2 = idx3 = 0 时, 值为 3

当i = 2; idx1 = 0, idx2 = 1, idx3 = 0 时, 值为 5

当i = 3; idx1 = 0, idx2 = 0, idx3 = 1 时, 值为 7

当i = 4; idx1 = 2, idx2 = 0, idx3 = 0 时, 值为 9

当i = 5; idx1 = 1, idx2 = 1, idx3 = 0 时, 值为 15

当i = 6; idx1 = 1, idx2 = 0, idx3 = 1 时, 值为 21

这不相当于 [1,3,9,27, ...], [1,5,25,125, ...], [1,7,49,345, ...] 三个数列的排列组合嘛

我们把每个数组都定义一个下标,然后从每个数组的第一元素开始乘,然后按照从小到大的顺序排列,我们会发现 3 x 5 和 5 x 3 是一样的,我们就需要去重了,也就是当前的值如果存在数组中,我们就把对应的下标加一,跳过就行了

/**
 * @param {number} k
 * @return {number}
 */
var getKthMagicNumber = function(k) {
    var idx1 = 0;
    var idx2 = 0;
    var idx3 = 0;
    var stash = new Array(k)
    stash[0] = 1
    for(let i = 1; i < k; i++){
        stash[i] = Math.min(stash[idx1] * 3, stash[idx2] * 5, stash[idx3] * 7)
        // 去重
        if(stash[i] == stash[idx1] * 3) idx1 ++;
        if(stash[i] == stash[idx2] * 5) idx2 ++;
        if(stash[i] == stash[idx3] * 7) idx3 ++;
    }
    return stash[k - 1]
};