几个月前在亚马逊招聘挑战中遇到了这个问题
给定两个数字a
和b
以及它们的倍数列表按升序排列,找到n
个倍数。
例如,如果a = 4 , b = 6
和n = 6
则答案为18
因为列表是4 6 8 12 16 18 20 24 28 30....
以下是我使用的方法:
选择较小的a
和b
。将它分配给小。将另一个分配给大。
生成a
和b
的倍数的列表(如上所示)
small*n
,因为所要求的答案不能大于此。
创建指向此列表中最后一个数字的指针。
将此指针移回较大数字的倍数,直至small*n
(只需将指针缩回(small * n)/big
)。
将指针向前移动a
和b
的最小公倍数,直至small * n
。这是必需的答案。
这种方法在小型测试用例上运行良好,但对较大的测试用例则有效。
请建议较少时间复杂的方法。由于某些原因,Mathjax无法在我的任何浏览器中使用。
答案 0 :(得分:3)
注意到,找到L=LCM(a,b)
(此处为12)
同时计算la = LCM/a, lb = LCM/b
(此处为3,2)
请注意,L代表行中的F = la + lb - 1
- 位置,而LCM的第k个倍数位于k * F
- 序列的位置(此处为k * 4)
所以你可以很容易地找到:
-interval,其中第n个成员是:idx = n div F
(此处6 div 4 = 1
从0开始)
-place在此时间间隔内:p = div mod F
(此处6 mod 4 = 2
从0开始)
现在你必须找到0..LCM - 1
范围内的第p项。请注意,您不需要构建列表(可能的方法 - 二进制搜索)
答案 1 :(得分:2)
我们可以进行简单的二分搜索,考虑到任意自然n
的倍数是floor(n / a) + floor(n / b) - floor(n / lcm(a, b))
。然后使用较小的result mod a
或result mod b
减去结果。
JavaScript代码:
function gcd(a,b){
while (b > 0)
[a, b] = [b, a % b];
return a;
}
function lcm(a, b){
return a * b / gcd(a, b);
}
function countMul(a, b, lcmAB, n){
return ~~(n / a) + ~~(n / b) - ~~(n / lcmAB);
}
function nthMul(a, b, n){
let low = Math.min(a,b);
let high = n * Math.min(a,b);
let mid = ~~((low + high) / 2);
let lcmAB = lcm(a, b);
while (countMul(a, b, lcmAB, mid) != n){
if (countMul(a, b, lcmAB, mid) > n)
high = mid;
else
low = mid;
mid = ~~((low + high) / 2);
}
return mid - Math.min(mid % a, mid % b);
}
console.log(nthMul(4,6,6));