查找数组的最大元素是另一个元素的除数

时间:2015-04-09 04:39:17

标签: arrays algorithm

给定一个长度为N的非零整数数组。写一个返回数组最大元素的函数,该元素是同一数组中某个其他元素的除数。如果此号码不存在,则返回0。我知道如何在O(n^2)中解决。是否可以更快地完成它?

3 个答案:

答案 0 :(得分:2)

首先,请注意您假设测试整数A除以整数B可以在O(1)中完成。我猜您也假设不允许预先计算(例如构建divisibility graph)。

由于integer factorization(不知道多项式算法)不是一个选项,因此你不能比O(n ^ 2)(最差情况)更快。

例如,给定输入{11,127,16139}(所有整数都是素数,每个整数的平方小于下一个),你就不能检查所有对。

答案 1 :(得分:1)

我一直在玩你的问题一段时间,发现了一个比蛮力更强的解决方案。

它基于创意:

  • 我们可以按顺序执行搜索,以便首先测试更大的除数候选。这样我们就可以在找到除数后立即终止搜索。

  • 测试某个候选divw是否为w的除数的一种方法是计算r = floor(w / divw),然后检查r * divw == w。有趣的是,当它失败时,我们可以将w的下一个除数候选者的上限计算为topw = floor(w / (r + 1))。因此,我们可以放弃divwtopw之间的任何内容。

第二点的示例:想象一下,我们正在测试divw = 10w = 12的除数,我们计算r = floor(12 / 10) = 1topw = floor(w / 2) = 6。因此,我们无需检查79之间的集合中的数字是否为12的除数。

为了实现这个算法,我使用了一个堆来保存集合中的数字,使用必须进行测试的下一个除数候选作为关键字。

因此...

  1. 初始化堆,将其前身的每个元素作为其较大的潜在除数。

  2. 弹出堆中的第一个元素(w)并检查潜在的除数候选(divw)是否实际上是除数。

  3. 如果是,请将其作为最大的除数

  4. topww计算divw;搜索集合divw'中等于或小于topw的下一个元素(使用二进制搜索);如果找到,请再次在队列中推送wdivw'

  5. 除非队列为空,请转到2

  6. Common Lisp中的实现可用here

    我想计算这个算法的理论计算成本会很有挑战性,特别是对于普通情况,所以我不打算这样做!

    在运行十几次之后,当N为高并且数字分散时(这意味着一个数字是另一个数的除数的概率很低),它似乎比蛮力方法表现得更好。另一方面,当N为低或数字密集分布在一个小范围内时,蛮力似乎更快(这意味着数字的概率是另一个的除数很高)。

答案 2 :(得分:0)

我这样做了

int f(int* a, int size)
{
    int max = 0;
    for (int i = 0; i < size; i++)
        for (int j = 0; j < size; j++)
            if (a[i] > a[j] && a[i] % a[j] == 0 && a[j] > max)
                max = a[j];
    return max;
}