两个数字的倍数列表的第n个数字

时间:2018-03-26 05:06:59

标签: algorithm

几个月前在亚马逊招聘挑战中遇到了这个问题 给定两个数字ab以及它们的倍数列表按升序排列,找到n个倍数。

例如,如果a = 4 , b = 6n = 6则答案为18 因为列表是4 6 8 12 16 18 20 24 28 30....

以下是我使用的方法:

  1. 选择较小的ab。将它分配给小。将另一个分配给大。

  2. 生成ab的倍数的列表(如上所示) small*n,因为所要求的答案不能大于此。

  3. 创建指向此列表中最后一个数字的指针。

  4. 将此指针移回较大数字的倍数,直至small*n(只需将指针缩回(small * n)/big)。

  5. 将指针向前移动ab的最小公倍数,直至small * n。这是必需的答案。

  6. 这种方法在小型测试用例上运行良好,但对较大的测试用例则有效。

    请建议较少时间复杂的方法。由于某些原因,Mathjax无法在我的任何浏览器中使用。

2 个答案:

答案 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 aresult 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));