「这是我参与11月更文挑战的第15天,活动详情查看:2021最后一次更文挑战」
题目
面试题 17.09. 第 k 个数
有些数的素因子只有 3,5,7,请设计一个算法找出第 k 个数。注意,不是必须有这些素因子,而是必须不包含其他的素因子。例如,前几个数按顺序应该是 1,3,5,7,9,15,21。
示例 1:
输入: k = 5
输出: 9
思路
-
这道题先得找规律,我看了半天才反应过来题目的意思,给大家翻译一下。一个数可以被3、5、7经过
n轮整除到1的,就是素因子:比如:
3 / 3 = 1、9 / 3 / 3 = 1、15 / 3 / 5 = 1。 -
找到规律后,这道题目就简单多了。我们只需要统计从
let result = [1]开始,每一轮拿3、5、7来乘以我们有的数,乘积也push进result中如此反复即可; -
但是发现有个坑,比如
3 * 9 < 5 * 5, 那么该推哪一个数呢? -
一开始我想用三个数组来代表每个数接下去可以乘的数,找到最小值后放进
result中; -
后面想了想发现没必要搞三个数组,只需要用三个变量来记录当前每个数乘到哪个位置了即可;
-
做完题目才发现,这就是三指针的概念。。。
-
整体来说,就是你每次拿数组中的元素从前往后, 分别*3、*5、*7,然后看到哪个小就先记录哪个。当然,相等的时候要把两个指针一起往后移位。比如:
3 * 5 = 5 * 3; -
最后由于数组从
0开始的,返回result[k-1]即可。
实现
/**
* @param {number} k
* @return {number}
*/
function getKthMagicNumber(k) {
let reuslt = [1, 3, 5, 7];
let index1 = index2 = index3 = 1;
while (reuslt.length < k) {
// 记录当前值
let cur3 = reuslt[index1] * 3,
cur5 = reuslt[index2] * 5,
cur7 = reuslt[index3] * 7;
if (cur3 <= cur5 && cur3 <= cur7) {
// 最小值是*3的,乘过后把当前值push进数组中,就是我们要的数
reuslt.push(cur3);
// 有相等的指针要以前往后移
if (cur3 === cur5) {
index2++;
}
if (cur3 === cur7) {
index3++;
}
index1++;
} else if (cur5 <= cur3 && cur5 <= cur7) {
reuslt.push(cur5);
if (cur5 === cur3) {
index1++;
}
if (cur5 === cur7) {
index3++;
}
index2++;
} else {
reuslt.push(cur7);
if (cur7 === cur3) {
index1++;
}
if (cur7 === cur5) {
index2++;
}
index3++;
}
}
return reuslt[k - 1];
};
结果
优化
写完后总觉得自己的代码不够优雅,重复的代码写了好几遍,于是痛定思痛,优化了一下代码。
/**
* @param {number} k
* @return {number}
*/
function getKthMagicNumber(k) {
let reuslt = [1];
let p1 = p2 = p3 = 0;
while (reuslt.length < k) {
// 这里三个变量是为了好理解,想优化空间复杂度可以不用变量的
let cur3 = reuslt[p1] * 3,
cur5 = reuslt[p2] * 5,
cur7 = reuslt[p3] * 7;
const minValue = Math.min(...[cur3, cur5, cur7]);
reuslt.push(minValue);
if (cur3 === minValue) p1++;
if (cur5 === minValue) p2++;
if (cur7 === minValue) p3++;
}
return reuslt[k - 1];
};
优化结果
看懂了的小伙伴可以点个关注、咱们下道题目见。如无意外以后文章都会以这种形式,有好的建议欢迎评论区留言。