如何在Javascript中计算自然数1到N的LCM?

时间:2015-07-30 23:18:46

标签: javascript algorithm modulo

所以,我的问题是找到从1到20均匀分配到所有数字的最小倍数。我确实成功地解决了这个任务,但我的程序运行得相当慢。这是代码,我使用的最终数字是1亿。 你可以想象,这需要很多时间。所以我想知道,我将如何优化此代码? 另外,知道如何更改它应该分成的数字是很好的,所以不要使用1到20,而是说1到15。

function smallestMultiple(n) {
    for (i = 0; i< n; i++) {
        if (i%1 === 0 && i%2 === 0 && i%3 === 0 && i%4 === 0 && i%5 === 0 
                 && i%6 === 0 && i%7 === 0 && i%8 === 0 && i%9 === 0 
                 && i%10 === 0 && i%11 === 0 && i%12 === 0 && i%13 === 0 
                 && i%14 === 0 && i%15 === 0 && i%16 === 0 && i%17 === 0 
                 && i%18 === 0 && i%19 === 0 && i%20 === 0 ) {

            console.log(i);
        }
    };
};

现在,显然,这需要5分钟才能找到答案。我想知道是否有更有效的方法? 编辑:显然我也可以使用1-20的变量。如果你有答案,请仔细解释你的答案以及为什么它更有效率。

3 个答案:

答案 0 :(得分:6)

我认为我发现了一个最优雅的解决方案,直接来自论坛:

  

如果没有真正尝试过,我会想到一些&#34;蛮力&#34;   这里的方法违反了&#34; 1分钟规则&#34;。但考虑到了   微小的变化可以大大提高算法的效率。

     

&#34;蛮力&#34;假设方法是:迭代每个自然   number - 如果电流可以被每个数字1整除   到了20岁,你找到了答案。

     

考虑一下:如果你知道N的解是X,那么   N + 1的解必须可被X整除。因此,迭代时   通过自然数,你可以迭代X而不是1   而不是检查数字1到N + 1的可分性,你   只需要检查N + 1,因为你已经知道了这些值   (X的倍数)都可以被1到N整除。

     

作为一个例子,假设10的答案是2520,那就得到了   解11,我们检查2520是否可以被11整除。它不是,   我们迭代到5040并检查它是否可以被11整除。我们继续   直到我们发现27720可被11整除,这就是答案。

     

尽管没有尝试直接确定LCD,但最终还是结束了   是一个相当快速的算法,在一秒钟内轻松运行   N值略大。

     

在Ruby中(尽管类似的方法可以在许多高级别中使用)   语言):

     

def snd(max)result = 1表示n在1..max       prev =结果       而结果%n> 0         结果+ = prev       结束返回结果

     

放snd(20)

然后我将其解释为Javascript并获得此脚本

&#13;
&#13;
console.log("Please type in smallestMultiple(n), whereas n is the smallest multiple.");

function smallestMultiple(n) {
   var result = 1;
   var prev;
   for (i=1; i<n+1; i++) {
       prev = result;
       while (result%i > 0) {
           result += prev;
       }
   }
   console.log(result);
};
&#13;
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>
&#13;
&#13;
&#13;

编辑:在脚本中发现错误,返回smallestNumber(11) = 2520.在for循环中修复:for(i = 0; i&lt; n + 1 ;我++)

答案 1 :(得分:3)

使用reduction by the greatest common divisor

的方法

跳过数字1 - 10,因为你可以将它们中的任何一个乘以2并获得列表中的另一个因子。

require 'open-uri' # Allows us to read the S3 content into the mail attachment.

class InvoiceMailer < ActionMailer::Base
  def send_invoice(user, invoice)
    @user = user
    @invoice = invoice
    attachments["invoice.pdf"] = open(@invoice.s3_url).read
    mail(to: @user.email, subject: "This Month's Invoice")
  end
end

为任意n做,而不是超级优化,但它很简单:

function GCF(a, b) {
    if (b == 0) return a;
    else return (GCF (b, a % b));
}

function LCM(a, b) {
    return Math.abs(a*b) / GCF(a, b);
}

LCM(11, LCM(12, LCM(13, LCM(14, LCM(15, LCM(16, LCM(17, LCM(18, LCM(19, 20)))))))));

答案 2 :(得分:0)

所以,你想要1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19的最小公倍数, 20

这与20,19,18,17,16,15,14,13,12,11的最小公倍数(LCM)相同,因为1,2,3,4,5,6,7, 8,9,10是其他十个数字的所有因素。

你应该使用while循环,因为它们更快。

LCM必须小于或等于20,19,18,17,16,15,14,13,12,11的倍数,因此n可以等于那个。{/ p>

i可以在序列中所有素数的倍数处开始:19 * 17 * 13 * 11 * 7 * 5 * 3 * 2

break退出循环。这可能是你花了这么长时间的原因。

我们可以增加20,因为它是答案之间可能的最小差异。

function lowestCommonMultipleof20Through1(){
  var i = 19*17*13*11*7*5*4*3; 
  var n = 20*19*18*17*16*15*14*13*12*11;
  while(i < n){
    if( i%11 === 0 && 
        i%12 === 0 && 
        i%13 === 0 && 
        i%14 === 0 && 
        i%15 === 0 && 
        i%16 === 0 &&
        i%17 === 0 &&
        i%18 === 0 &&
        i%19 === 0 &&
        i%20 === 0 ){
      console.log(i);
      break;
    }
    i+=20;
  }
}

我几乎立刻得到了232792560。