删除每个元素可以划分数组中的另一个元素

时间:2014-01-24 04:42:21

标签: c++

我正在咨询StackOverflow的天才。我已经坚持使用我正在编写的算法来返回两个或更多数字的最小公倍数(LCM)。

例如,LCM(3,4,6)= 24,LCM(2,2,2)= 2,LCM(8,9)= 72等。

这是我想要使用的程序(除非你有更好的想法):

(1)将数组复制到一个向量中(因为我们需要它在步骤3中是动态的)

(2)对矢量进行排序(这将使第3步更容易)

(3)删除分成另一个元素的每个元素(例如,如果您尝试计算LCM(3,4,6),则3是冗余的,因为LCM(3,4,6)= LCM(4 ,6))

(4)计算数组中每个元素的乘积

第3步是我在编写优雅程序时遇到的问题,因为所有删除操作都会改变向量的大小而等等。

int LCM(int* numsPtr, size) { 
    assert(size > 1);
    std::vector<int> numsVec(numsPtr, numsPtr + size); // need to work with copy of the array
    for (int k = 0; k < size; ++k)
        numsVec[k] = numsPtr[k];
    std::sort(numsVec, numsVec + size);
    // What now????
} 

顺便说一句,这是我在Project Euler Problem 5

中尝试的一部分

我已经采用了蛮力的方式

// -------------------- Brute force --------------------
int n = 20;
int k = n;
while (true) { 
// divisors to cross off:   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
    if (   (k % 20 == 0) // 3 6 7 8 9 11 12 13 14 15 16 17 18 19
        && (k % 19 == 0) // 3 6 7 8 9 11 12 13 14 15 16 17 18
        && (k % 18 == 0) // 7 8 11 12 13 14 15 16 17
        && (k % 17 == 0) // 7 8 11 12 13 14 15 16
        && (k % 16 == 0) // 7 11 12 13 14 15
        && (k % 15 == 0) // 7 11 12 13 14
        && (k % 14 == 0) // 11 12 13
        && (k % 13 == 0) // 11 12
        && (k % 12 == 0) // 11
        && (k % 11 == 0)    )
        break;
    ++k;
}
std::cout << "The smallest number divisible by 1, 2, ..., " << n << " is " << k << std::endl;

我正试图改进它。

1 个答案:

答案 0 :(得分:2)

这可能不是最有用的答案,但考虑到计算整数序列的LCM的问题,我会以不同的方式处理问题。

从学校数学,你可能还记得

GCD(m, n) * LCM(m, n) = m*n

因此,对于两个整数,我们有一种方法可以用最大公约数来计算最小公倍数。使用众所周知的欧几里德算法可以很容易地计算GCD。

所以现在我们为任意整数序列提供了LCM算法的基本原理:

  1. mn成为序列的前两个元素

  2. 设置m = m * n/GCD(m, n)

  3. n设置为序列的下一个元素,然后转到2.

  4. 返回m

  5. 即。我们计算第一对的LCM,然后计算该结果的LCM和序列的下一个元素,依此类推。

    我不知道这是否是最佳的,但它不需要动态存储或元素排序,所以它应该比上面的解决方案更快。

    (另外,另外,我很确定LCM(3,4,6)= 12,而不是24 :-))

    编辑:我发现这个问题很有趣,可以解决问题,所以我也可以分享一下......

    #include <iostream>
    #include <vector>
    
    template <typename T>
    inline T gcd(T a, T b)
    {
        while (b != 0) {
            T t = b;
            b = a % b;
            a = t;
        }    
        return a;
    }
    
    template <typename Iter>
    inline auto
    lcm(Iter start, Iter end)
        -> typename std::iterator_traits<Iter>::value_type
    {
        using value_type = typename std::iterator_traits<Iter>::value_type;
    
        if (start == end) return 0; // empty sequence
    
        value_type m{*start};
    
        while (++start != end) {
            value_type n{*start};
            m = m * n / gcd(m, n);
        }
        return m;
    }
    
    int main()
    {
        std::vector<int> v{3, 4, 20, 5, 12, 15};
        std::cout << lcm(v.begin(), v.end()) << std::endl; // prints 60
    }
    

    当然欢迎评论和更正: - )