为什么这两种算法的运行时间有所不同?

时间:2019-07-25 16:28:04

标签: java performance prime-factoring

作为一个较大问题的一部分,我必须找到整数n的素数因子之和。我写了自己的版本,但是我对问题的解决方法超时了。我在网上看了一下,发现同一种方法的不同版本,将一个整数的素因子相加,当我只改变其中一种方法时,解决方案就足够快了。但是,仅基于代码,我发现运行时间没有任何区别。

我的(较慢的)版本:

static int factors(int n) {
        int total = 0;
        while (n % 2 == 0) {
            total += 2;
            n /= 2;
        }
        int j = 3;
        while (n > 1) {
            while (n % j == 0) {
                total += j;
                n /= j;
            }
            j += 2;
        }
        return total;
    }

我发现的(更快的)版本:

static int factors(int n) {
        int sum = 0;
        int i = 2;
        while (true) {
            if (n % i == 0) {
                n /= i;
                sum += i;
                if (isPrime(n)) {
                    sum += n;
                    break;
                }
                i = 1;
            }
            i++;
        }
        return sum;
    }

为简洁起见,我没有在底部的方法中加入isPrime方法;这只是循环到sqrt(n)的基本暴力手段,甚至不是Eratosthenes的筛子。

如果有的话,我本来以为我的版本会更快,因为它可以消除素数因子的所有重复项,也不需要重复测试数字是否为素数。

3 个答案:

答案 0 :(得分:1)

我相信这取决于您的输入

我认为,在纸上,这两种算法的复杂度是相同的:O(n log(n))(假设isPrime(n)的复杂度为O(log(n))-请问是否有人在计算方面比我好大O可以确认或否认这会很棒),因此它们应该相当相等,但是如您所知,此分析需要假设最坏的情况。

在实践中:

例如假设您的数字n是3 ^ 1000,您的方法会将其除以3大约1000次,第二种方法将其除以3,然后是9,然后是27,依此类推,从而减少了所需的操作数。 / p>

通常,我会假设,如果在n中多次存在相同的因素,则您的方法会更慢。

答案 1 :(得分:0)

您的算法有错误。您总是在添加j += 2。但是主要因素仅增加了2个,达到13个。下一个是17个(而不是15个)。 您走得更远-质数之间的平均步长更长。 在您的算法中,您总是步步为2。

以下是1000的主要因素:

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 601 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691 701 709 719 727 733 739 743 751 757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997 1009

在您的算法中,您将有500个数字(以2为步长)。

因此,如果您的数量很大-您将拥有比第二种算法更多的迭代次数。

答案 2 :(得分:0)

第二种方法从早期中断中获利,而您的方法一直迭代直到j到达n。对于大n,这需要花一些时间。...

使用类似while (n > 1 && n <= j * j)的条件,因此您可以在sqrt(n)左右而不是n处突破(我的意思是原始n作为参数给出,而不是当前的值)。

由于情况的第二部分而退出时,请不要忘记n > 1是最后一个因素。