【问题标题】:What is the most efficient way to calculate the least common multiple of two integers?计算两个整数的最小公倍数的最有效方法是什么?
【发布时间】:2011-03-10 10:15:23
【问题描述】:

计算两个整数的最小公倍数最有效的方法是什么?

我只是想出了这个,但它肯定还有一些不足之处。

int n=7, m=4, n1=n, m1=m;

while( m1 != n1 ){
    if( m1 > n1 )
        n1 += n;
    else 
        m1 += m;
}

System.out.println( "lcm is " + m1 );

【问题讨论】:

    标签: math


    【解决方案1】:

    ab 的最小公倍数 (lcm) 是它们的乘积除以它们的最大公约数 (gcd)(即 lcm(a, b) = ab/gcd(a,b))。

    那么,问题就变成了,如何找到gcd? Euclidean algorithm 通常是 gcd 的计算方式。经典算法的直接实现是有效的,但有一些变体利用二进制算术做得更好。请参阅Knuth 的“The Art of Computer ProgrammingVolume 2, "Seminumerical Algorithms" § 4.5.2

    【讨论】:

    • 是的,使用 GCD 的 LCM 快速且易于编码。一个小而重要的细节:为了避免溢出,计算最终结果如下:lcm = a / gcd * b 而不是 lcm = a * b / gcd
    • @Bolo - 如果您“担心”溢出,您应该使用long 或在其他情况下甚至使用BigInteger。两个int 值的LCM 可能是long
    • @Stephen C 使用 Bolo 的方法,如果可以表示 LCM,则可以在不溢出的情况下计算 LCM。没有必要只为乘法使用更大更慢的数字类型。
    • @starblue - 但相反,LCM 可以 表示为int 的问题没有任何意义。而且我们知道,对于mn 的某些值,它不能。我的观点是,如果您担心计算中的溢出,您应该担心最终结果中的溢出。
    • @Stephen C 可能会发生两个输入整数的顺序为 O(N) 并且它们的 LCM 顺序为 O(N)。在原始方法中,中间结果的顺序为 O(N^2),而在修改后的方法中仅为 O(N)。示例:p = 2^31 - 1 = 2147483647,m = 2*p,n = 3*p。它们的 LCM = 6*p,这些都不是很大的数(long 可以表示最大为 2^63 - 1 = 9223372036854775807 的整数),但原来的方法无论如何都会溢出(中间值为 6*p*p)。无论类型如何(shortintlong),简单的重新排序都可以大大提高算法的适用性。
    【解决方案2】:

    记住 最小公倍数是两个或多个数字的倍数的最小整数。

    如果您要计算三个整数的 LCM,请按以下步骤操作:

      **Find the LCM of 19, 21, and 42.**
    

    写出每个数字的素数分解。 19是质数。您不需要考虑 19。

    21 = 3 × 7
    42 = 2 × 3 × 7
    19
    

    重复每个质因数,使其在上述任何质因数分解中出现的次数最多。

    2 × 3 × 7 × 19 = 798

    21、42 和 19 的最小公倍数是 798。

    【讨论】:

    【解决方案3】:

    我认为“reduction by the greatest common divider”的方法应该更快。首先计算 GCD(例如使用Euclid's algorithm),然后将两个数字的乘积除以 GCD。

    【讨论】:

      【解决方案4】:

      下面C++中不溢出的最佳解决方案

      #include <iostream>
      using namespace std; 
      long long gcd(long long int a, long long int b){        
          if(b==0)
              return a;
          return gcd(b,a%b);
      }
      
      long long lcm(long long a,long long b){     
          if(a>b)
              return (a/gcd(a,b))*b;
          else
              return (b/gcd(a,b))*a;    
      } 
      
      int main()
      {
          long long int a ,b ;
          cin>>a>>b;
          cout<<lcm(a,b)<<endl;        
          return 0;
      }
      

      【讨论】:

        【解决方案5】:

        首先,你必须找到最大公约数

        for(int i=1; i<=a && i<=b; i++) {
        
           if (i % a == 0 && i % b == 0)
           {
               gcd = i;
           }
        
        }
        

        之后,使用 GCD 你可以很容易地找到像这样的最小公倍数

        lcm = a / gcd * b;
        

        【讨论】:

        • 从两个数字中的较低者开始迭代到零会更快吗?这样,您可以避免遍历整个集合。 for (int i = a; i &gt;= 0; i--) 之类的东西,然后如果该 if 语句返回 true,则可以跳出循环。
        【解决方案6】:

        不知道有没有优化,但可能是最简单的一个:

        public void lcm(int a, int b)
        {
            if (a > b)
            {
                min = b;
                max = a;
            }
            else
            {
                min = a;
                max = b;
            }
            for (i = 1; i < max; i++)
            {
                if ((min*i)%max == 0)
                {
                    res = min*i;
                    break;
                }
            }
            Console.Write("{0}", res);
        }
        

        【讨论】:

          【解决方案7】:

          这是一种在python中找到两个数字的LCM的高效方法。

          def gcd(a, b):
              if min(a, b) == 0:
                  return max(a, b)
              a_1 = max(a, b) % min(a, b)
              return gcd(a_1, min(a, b))
          
          def lcm(a, b):
              return (a * b) // gcd(a, b)
          

          【讨论】:

            【解决方案8】:

            使用欧几里得算法找到 gcd 然后计算 lcm 除以 gcd 和 b 的乘积对我有用。

            int euclidgcd(int a, int b){
                    if(b==0)
                    return a;
                    int a_rem = a % b;
                    return euclidgcd(b, a_rem);
                    }
                
            long long lcm(int a, int b) {
                    int gcd=euclidgcd(a, b);
                    return (a/gcd*b);
                    }
            
            int main() {
                  int a, b;
                  std::cin >> a >> b;
                  std::cout << lcm(a, b) << std::endl;
                return 0;           
                }
            

            【讨论】:

              【解决方案9】:

              取两个数中较大者的连续倍数,直到结果是较小者的倍数。

              这可能有效..

                 public int LCM(int x, int y)
                 {
                     int larger  = x>y? x: y,
                         smaller = x>y? y: x,
                         candidate = larger ;
                     while (candidate % smaller  != 0) candidate += larger ;
                     return candidate;
                 }
              

              【讨论】:

              • 这适用于 x 和 y 的小值,但很难缩放。
              • 老兄,这有助于解决欧几里得算法导致堆栈溢出的挑战。我想把它放大你只是把它们当作字符串并具有模数和加法的功能?
              【解决方案10】:

              C++ 模板。编译时间

              #include <iostream>
              
              const int lhs = 8, rhs = 12;
              
              template<int n, int mod_lhs=n % lhs, int mod_rhs=n % rhs> struct calc {
                calc() { }
              };
              
              template<int n> struct calc<n, 0, 0> {
                calc() { std::cout << n << std::endl; }
              };
              
              template<int n, int mod_rhs> struct calc<n, 0, mod_rhs> {
                calc() { }
              };
              
              template<int n, int mod_lhs> struct calc <n, mod_lhs, 0> {
                calc() { }
              };
              
              template<int n> struct lcm {
                lcm() {
                  lcm<n-1>();
                  calc<n>();
                }
              };
              
              template<> struct lcm<0> {
                lcm() {}
              };
              
              int main() {
                lcm<lhs * rhs>();
              }
              

              【讨论】:

                【解决方案11】:

                欧几里得GCD码sn-p

                int findGCD(int a, int b) {
                        if(a < 0 || b < 0)
                            return -1;
                
                        if (a == 0)
                            return b;
                        else if (b == 0)
                            return a;
                        else 
                            return findGCD(b, a % b);
                    }
                

                【讨论】:

                • OP 正在寻找 LCM
                【解决方案12】:

                2 个数字的乘积等于 LCM * GCD 或 HCF。所以找LCM最好的办法就是找GCD,用GCD来划分产品。即LCM(a,b) = (a*b)/GCD(a,b)。

                【讨论】:

                • GDC?你是说 GCD 吗?
                • 无论如何,这听起来像是对现有答案的重复。
                【解决方案13】:

                没有比使用内置函数更高效的方法了!

                从 Python 3.8 开始,lcm() 函数已添加到数学库中。并且可以使用以下签名调用:

                math.lcm(*integers)
                

                返回指定整数参数的最小公倍数。如果所有参数都不为零,则返回值是所有参数的倍数的最小正整数。如果任何参数为零,则返回值为 0。不带参数的 lcm() 返回 1。

                【讨论】:

                  【解决方案14】:

                  扩展@John D. Cook 答案,该答案也标记为该问题的答案。 (https://stackoverflow.com/a/3154503/13272795),我正在共享算法来查找 n 个数字的 LCM,它可能是 2 个数字或任何数字的 LCM。此代码的来源是this

                   int gcd(int a, int b)
                   {
                       if (b == 0)
                           return a;
                       return gcd(b, a % b);
                   }
                  
                    // Returns LCM of array elements
                   ll findlcm(int arr[], int n)
                   {
                      // Initialize result
                       ll ans = arr[0];
                  
                     // ans contains LCM of arr[0], ..arr[i]
                     // after i'th iteration,
                         for (int i = 1; i < n; i++)
                             ans = arr[i] * ans/gcd(arr[i], ans);
                         return ans;
                   }
                  

                  【讨论】:

                    【解决方案15】:

                    先用功效法计算GCD,然后用这个公式从gcd中得到lcm

                                            lcm = (n1 * n2) / gcd;
                    

                    对于 GCD 的计算,我们使用这个逻辑

                            for (int i = 1; i <= n1 && i <= n2; ++i) {
                                    if (n1 % i == 0 && n2 % i == 0)
                                        gcd = i;
                             } 
                    

                    我们也可以calculate LCM using recursion 。这是使用 gcd 查找 lcm 的 java 示例。

                      public class LCMUsingGCD {
                          public static void main(String[] args) {
                    
                        int n1 = 40, n2 = 50, gcd = 1;
                    
                        for (int i = 1; i <= n1 && i <= n2; ++i) {
                            if (n1 % i == 0 && n2 % i == 0)
                                gcd = i;
                        }
                    
                        int lcm = (n1 * n2) / gcd;
                        System.out.println("LCM  :" + lcm + " of n1 : " + n1 + " and n2 : "
                                + n2);
                    }
                    

                    }

                    【讨论】:

                      【解决方案16】:

                      因为我们知道 “任意两个数的 LCM 和 HCF 的乘积等于这两个数的乘积”的数学性质。

                      假设 X 和 Y 是两个整数, 然后 X * Y = HCF(X, Y) * LCM(X, Y)

                      现在我们可以通过知道 HCF 来找到 LCM,我们可以通过欧几里得算法找到。

                        LCM(X, Y) = (X * Y) / HCF(X, Y)
                      

                      希望这将是有效的。

                      import java.util.*;
                      public class Hello {
                          public static int HCF(int X, int Y){
                              if(X == 0)return Y;
                              return HCF(Y%X, X);
                          }
                          public static void main(String[] args) {
                              Scanner scanner = new Scanner(System.in);
                              int X = scanner.nextInt(), Y = scanner.nextInt();
                              System.out.print((X * Y) / HCF(X, Y));
                          }
                      }
                      

                      【讨论】:

                        猜你喜欢
                        • 2022-11-27
                        • 2011-05-12
                        • 2014-11-08
                        • 2018-12-07
                        • 1970-01-01
                        • 1970-01-01
                        • 2011-07-13
                        • 2012-08-14
                        • 2013-01-23
                        相关资源
                        最近更新 更多