给定一组数字,找到具有最小LCM(最低公倍数)的对

时间:2016-11-14 07:39:37

标签: c algorithm math number-theory lcm

我使用了这种方法。

  1. 找到n个数字可能的所有 nC2对
  2. 然后通过计算 GCD并将两个数字的乘积除以GCD来单独找到 LCM
  3. 还维护一个变量,该变量包含到那时计算的最小LCM值,最后输出它。
  4. 但是当数值非常大(~10 ^ 9)时,这种天真的方法看起来效率很低,因为GCD的时间复杂度将取决于数字的大小。对于非常大的N值也是不可行的。 还有其他更好的解决方法吗?

2 个答案:

答案 0 :(得分:0)

我认为没有一种有效的算法。

你总是可以使用启发式和简单的方法来解决这个问题。

平均而言,对于大多数阵列,这对数字将类似于a,b(a

因此,平均而言,LCM不会非常大并且与阵列的元素类似。

所以,Idea就是对数组进行排序,然后首先尝试使用较小的a,b。当b> lcm_so_far

由于

答案 1 :(得分:0)

对于大量数字,有效实现欧几里德算法(https://en.wikipedia.org/wiki/Euclidean_algorithm#Algorithmic_efficiency)以找到GCD是我能想到的最佳路线。没有用于素数分解的快速通用算法,因此使用它来减少问题将无助于运行时间。我不知道有任何快速减少会对此有所帮助。

解决大N问题,我认为这是其他人所得到的:

  1. 对数组进行排序
  2. 以最低值开始并使用短路计算LCM(使用欧几里德算法,例如GCD部分):一旦其余对的LCM不能小于目前为止的最佳值,则停止处理。注意,对于有序集合中的两个数字,b< c,LCM的下限是(b * c)/ b = c(这在b除以c时发生)。请参阅下面的工作代码(short_lcm版本)。
  3. 可以对此进行其他优化(例如不在python中编写:)但这证明了算法的改进:

    import fractions
    
    def lcm(a, b):
        return abs(a * b) / fractions.gcd(a, b)
    
    def short_lcm(a):
        a = sorted(a)
    
        iterations = 0
        cur_lcm = lcm(a[0], a[1])
        first = a[0]
        second = a[1]
        for i in range(0, len(a)):
            #Best case for remaining pairs
            if i < len(a) - 1 and a[i + 1] >= cur_lcm: break
    
            for j in range(i + 1, len(a)): #Starting at i + 1 avoids duplicates
                if a[j] >= cur_lcm: break  #Best case for remaining pairs
    
                iterations += 1
    
                test = lcm(a[i], a[j])
                if test < cur_lcm:
                    cur_lcm = test
                    first = a[i]
                    second = a[j]
    
        if iterations < 1: iterations = 1
    
        print("Lowest LCM pair is (%d, %d): %d. Found in %d iterations" % (
                    first, second, cur_lcm, iterations))
    
    def long_lcm(a):
        iterations = 0
        cur_lcm = lcm(a[0], a[1])
        first = a[0]
        second = a[1]
        for i in range(0, len(a)):
            for j in range(i + 1, len(a)):     #Starting at i + 1 avoids duplicates
                iterations += 1
    
                 test = lcm(a[i], a[j])
                if test < cur_lcm:
                    cur_lcm = test
                    first = a[i]
                    second = a[j]
    
        print("Lowest LCM pair is (%d, %d): %d. Found in %d iterations" % (
                    first, second, cur_lcm, iterations))
    
    if __name__ == '__main__':
        from random import randint
        import time
    
        a = [randint(1, 1000) for r in xrange(100)]
    
        #Only print the list if it's relatively short
        if len(a) < 20: print a
    
        #Try all pairs
        start = time.clock()
        long_lcm(a)
        print "Slow version time: %f\n" % (time.clock() - start)
    
        start = time.clock()
        short_lcm(a)
        print "Fast version time: %f" % (time.clock() - start)