如何优化因子计数算法

时间:2013-09-15 22:13:53

标签: java algorithm optimization

我被要求将除1之外的因子和数组中每个数字的数字本身相加。问题是它必须能够处理非常大的数组,并且对于大小为100,000,000的数组,我当前的实现需要很长时间。我计算每个数字因子的代码是

static long countFactors(long num){
    long count=0;
    long max =(long) Math.floor(Math.sqrt(num));
    for(int i=2; i<=max;i++){
        if(num%i==0&&(i*i)!=num){
            // count i and n/i as a factor
            count+=2;
            if(num/i<max){
                max=num/i;
            }
        }            
        else if(num%i==0){
            // just add one factor since it is the numbers root.
            count+=1;

        }
    }

    return count;
}

有没有人有任何优化建议。

4 个答案:

答案 0 :(得分:2)

我在这篇文章的开头就提出了最好的想法:

可被n整除的数字可被n的所有因素整除。

也许这是降低时间复杂度的关键。剩下的就是:

现在只需执行一次即可执行测试(i*i)!=num O(max)次。 (for(int i=2; i**<**max;i++)然后检查平方根)。你确实说过非常大的数字,所以这可以节省一点。

这又是什么? if(num/i<max){ max=num/i; }如果我正确阅读,这是多余的。此循环中的因子i绝不会超过num的平方根。

最后,在空间允许的情况下,您可以将外部循环放在i上,将循环放在内部的数组中。通过不需要重复i*i,这将节省一点点。这些只是对当前算法的微优化。

答案 1 :(得分:1)

很难回答这个问题,因为很难确切地知道问题是什么。一些评论如下。如果问题得到澄清,我可能会给出更好的答案。

1)目前尚不清楚你是否想要数字 n 的不同素数因子,具有多重性的素数因子或数字的除数。例如,给定数字 n = 12,不同的素数因子是2和3,其多重性的素因子是2,2和3,除数是1,2,3,4你的程序回答了关于除数的问题,所以我认为这就是你想要的,但你也提到你要从列表中消除1和 n ,这是不寻常的。

2)在不同的时间,你提到因素的计数和因子的总和。请准确说明你想要的东西。

3)目前尚不清楚您是否正在处理长度为10 ^ 8或 n 大到10 ^ 8的数组。如果你的数组长度为10 ^ 8,那么无论你做什么都需要一段时间。如果你有一个小得多的数组,比如一千个数字 n ,每个小于10 ^ 8,这就变得简单得多了。

假设你想要除数,这是一个函数,它将 n 的因子与它们的多重性相对应,并返回 n 的除数的和与计数。如果需要,您可以从计数中减去2,从总和中减去 n +1,以排除1和 n

function divSumCount(n)
    mult, sum, count, prev := 2, 1, 1, 0
    for fact in sort(factors(n))
        if fact == prev
            mult := mult + 1
        else if prev <> 0
            sum := sum * (prev ** mult - 1) / (prev - 1)
            count := count * mult
            mult := 2
        prev := fact
    sum := sum * (prev ** mult - 1) / (prev - 1)
    count := count * mult
    return sum, count

这是伪代码,我将留给你翻译成Java。假设 n 不大于10 ^ 8,这里有一个简单的程序,它使用试验除法计算 n ,返回按递增顺序排序的因子;如果 n 较大,您需要一个更好的算法来查找其因素:

function factors(n)
    f, fs := 3, []
    while n % 2 == 0
        append 2 to fs
    while f * f <= n
        while n % f == 0
            append f to fs
            n := n / f
        f := f + 2
    if n > 1 append n to fs
    return fs

4)如果数字 n 在数组中是连续的,例如从54813000到54823000,你可以筛选因子而不是费力地分解每个 n ,这将是要快得多。

如果您需要更多信息,请与我们联系。

答案 2 :(得分:0)

CAVEAT EMPTOR:这是一个我没有用基准测试的想法,所以它可能不是一个好的解决方案。

对于单个数字,您的代码非常好。但是如果你必须找到许多数字的因素,那么找到主要因素是一个很好的解决方案。

我的想法就像这样

1)从列表中找到您必须处理的最大数字(最大值)。

2)找到介于1和最大/ 2之间的素数(这是困难的部分,但只进行一次)。

3)你分析素数因子中的每个数字,例如。 150是2 * 3 * 5 * 5

4)所有因素都是素数因子的组合,在这种情况下它们是

*)2

*)2 * 3 = 6

*)2 * 5 = 10

*)2 * 3 * 5 = 30

*)2 * 5 ^ 2 = 50

*)3

*)3 * 5 = 15

*)3 * 5 ^ 2 = 75

*)5

*)5 ^ 2 = 25

优点是你只检查质数,这只是数字的一部分(如果你的数字变大,则减少一个)。无效是计算非素因子的最后一步,以及计算素数的时间(和记忆)(尽管你可能会将它们预先计算并存储在文件中一定的大小)。

答案 3 :(得分:0)

我可能会后悔这一点,但我会试一试。我假设你有足够的RAM /交换,并且更担心计算时间。我也假设你真的想要主要因素,而不是所有因素。

我要做的第一件事是对数组进行排序并确定唯一值。然后,我将尝试使用数组sieve构造Sieve of Eratosthenes,以识别(排序)唯一值数组中最大值的平方根的所有素数。我还会将所有数字的并行数组保持为最大值,将其称为sum_array,并将其初始化为全零。当我逐步通过sieve数组来屏蔽当前值的所有倍数时,我也会在相同的索引处逐步执行sum_array并将当前素数添加到并行的每个元素的运行总计中屏蔽sieve数组中该素数的倍数。

由于我真的不知道这是为了什么,所以我已经完成了除此之外的建议。