计算所有数字的除数的数量,直到N.

时间:2017-12-15 07:01:02

标签: java algorithm math

  

我需要计算1 to n范围内每个数字的所有除数。我在下面写了一个实现,给定一个整数num,它计算num的除数。其复杂性为O(sqrt(n))。因此,所有复杂性都是O(n * sqrt(n))。可以减少吗?如果是,那么你可以给出一个算法吗?

代码

 public static int countDivisors(int num)
    {
        int limit = (int)Math.sqrt(num);
        int count = 2;
        for(int i = 2 ; i <= limit ; i++)
        {
            if(num % i == 0)
            {
                count++;
                if(num / i != i)
                {
                    count++;
                }
            }
        }
        return count;
    }

PS:
此函数将被称为n次。

2 个答案:

答案 0 :(得分:2)

你可以使用一般化的Sieve of Eratosthenes改进天真的方法。而不是仅仅将数字标记为复合也存储它找到的第一个除数(我在下面的函数computeDivs中执行此操作)。

12-18 12:01:39.133  4279  4304 W javafx  : Loading FXML document with JavaFX API of version 8.0.102 by JavaFX runtime of version 8.0.72-ea
12-18 12:01:39.205  4279  4304 W System.err: Exception in Application start method
12-18 12:01:39.207  4279  4304 I System.out: QuantumRenderer: shutdown
12-18 12:01:39.208  4279  4299 W System.err: java.lang.reflect.InvocationTargetException
12-18 12:01:39.208  4279  4299 W System.err:    at java.lang.reflect.Method.invoke(Native Method)
12-18 12:01:39.208  4279  4299 W System.err:    at javafxports.android.DalvikLauncher$1.run(DalvikLauncher.java:188)
12-18 12:01:39.208  4279  4299 W System.err:    at java.lang.Thread.run(Thread.java:818)
12-18 12:01:39.208  4279  4299 W System.err: Caused by: java.lang.RuntimeException: Exception in Application start method
12-18 12:01:39.208  4279  4299 W System.err:    at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
12-18 12:01:39.208  4279  4299 W System.err:    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$138(LauncherImpl.java:182)
12-18 12:01:39.208  4279  4299 W System.err:    at com.sun.javafx.application.LauncherImpl.access$lambda$1(LauncherImpl.java)
12-18 12:01:39.208  4279  4299 W System.err:    at com.sun.javafx.application.LauncherImpl$$Lambda$2.run(Unknown Source)
12-18 12:01:39.208  4279  4299 W System.err:    ... 1 more
12-18 12:01:39.208  4279  4299 W System.err: Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/android/gms/R$string;
12-18 12:01:39.209  4279  4299 W System.err:    at com.google.android.gms.common.internal.zzca.<init>(Unknown Source)
12-18 12:01:39.209  4279  4299 W System.err:    at com.google.firebase.FirebaseOptions.fromResource(Unknown Source)
12-18 12:01:39.209  4279  4299 W System.err:    at com.google.firebase.FirebaseApp.initializeApp(Unknown Source)
12-18 12:01:39.209  4279  4299 W System.err:    at com.application.FirebaseInit.startup(FirebaseInit.java:21)
12-18 12:01:39.209  4279  4299 W System.err:    at com.application.control.SignupController.initialize(SignupController.java:36)
12-18 12:01:39.209  4279  4299 W System.err:    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2548)
12-18 12:01:39.209  4279  4299 W System.err:    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
12-18 12:01:39.209  4279  4299 W System.err:    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3214)
12-18 12:01:39.209  4279  4299 W System.err:    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3175)
12-18 12:01:39.209  4279  4299 W System.err:    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3148)
12-18 12:01:39.209  4279  4299 W System.err:    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3124)
12-18 12:01:39.209  4279  4299 W System.err:    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3104)
12-18 12:01:39.209  4279  4299 W System.err:    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3097)
12-18 12:01:39.209  4279  4299 W System.err:    at com.application.scenes.SignupPresenter.getView(SignupPresenter.java:17)
12-18 12:01:39.209  4279  4299 W System.err:    at com.application.Main.start(Main.java:40)
12-18 12:01:39.209  4279  4299 W System.err:    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$145(LauncherImpl.java:863)
12-18 12:01:39.209  4279  4299 W System.err:    at com.sun.javafx.application.LauncherImpl.access$lambda$8(LauncherImpl.java)
12-18 12:01:39.209  4279  4299 W System.err:    at com.sun.javafx.application.LauncherImpl$$Lambda$9.run(Unknown Source)
12-18 12:01:39.209  4279  4299 W System.err:    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$158(PlatformImpl.java:326)
12-18 12:01:39.209  4279  4299 W System.err:    at com.sun.javafx.application.PlatformImpl.access$lambda$6(PlatformImpl.java)
12-18 12:01:39.209  4279  4299 W System.err:    at com.sun.javafx.application.PlatformImpl$$Lambda$7.run(Unknown Source)
12-18 12:01:39.209  4279  4299 W System.err:    at com.sun.javafx.application.PlatformImpl.lambda$null$156(PlatformImpl.java:295)
12-18 12:01:39.210  4279  4299 W System.err:    at com.sun.javafx.application.PlatformImpl.access$lambda$18(PlatformImpl.java)
12-18 12:01:39.210  4279  4299 W System.err:    at com.sun.javafx.application.PlatformImpl$$Lambda$19.run(Unknown Source)
12-18 12:01:39.210  4279  4299 W System.err:    at java.security.AccessController.doPrivileged(AccessController.java:52)
12-18 12:01:39.210  4279  4299 W System.err:    at com.sun.javafx.application.PlatformImpl.lambda$runLater$157(PlatformImpl.java:294)

您还可以查看在ideone here上执行的代码。

简而言之,我使用筛子来计算每个数字的最大素数因子。使用这个我可以非常有效地计算每个数字的因子分解(我在countDivisors中使用它)。

很难计算筛子的复杂程度,但标准估计值为class Main { // using Sieve of Eratosthenes to factorize all numbers public static int[] computeDivs(int size) { int[] divs = new int[size + 1]; for (int i = 0; i < size + 1; ++i) { divs[i] = 1; } int o = (int)Math.sqrt((double)size); for (int i = 2; i <= size; i += 2) { divs[i] = 2; } for (int i = 3; i <= size; i += 2) { if (divs[i] != 1) { continue; } divs[i] = i; if (i <= o) { for (int j = i * i; j < size; j += 2 * i) { divs[j] = i; } } } return divs; } // Counting the divisors using the standard fomula public static int countDivisors(int x, int[] divs) { int result = 1; int currentDivisor = divs[x]; int currentCount = 1; while (currentDivisor != 1) { x /= currentDivisor; int newDivisor = divs[x]; if (newDivisor != currentDivisor) { result *= currentCount + 1; currentDivisor = newDivisor; currentCount = 1; } else { currentCount++; } } if (x != 1) { result *= currentCount + 1; } return result; } public static int countAllDivisors(int upTo) { int[] divs = computeDivs(upTo + 1); int result = 0; for (int i = 1; i <= upTo; ++i) { result += countDivisors(i, divs); } return result; } public static void main (String[] args) throws java.lang.Exception { System.out.println(countAllDivisors(15)); } } 。此外,我非常有信心不可能改善这种复杂性。

答案 1 :(得分:1)

通过使用简单的迭代,您可以比O(n.sqrt(n))做得更好。代码是用C ++编写的,但你可以很容易地理解它。

#include <iostream>
#include <vector>
using namespace std;

void CountDivisors(int n) {
    vector<int> cnts(n + 1, 1);
    for (int i = 2; i <= n; ++i) {
        for (int j = i; j <= n; j += i) {
            cnts[j]++;
        }
    }
    for (int i = 1; i <= n; ++i) {
        cout << cnts[i] << " \n"[i == n];
    }
}

int main() {
    CountDivisors(100);
    return 0;
}

运行时间为n/1 + n/2 + n/3 + n/4 + ... + n/n,可以O(nH(n))近似,其中H(n)harmonic series。我认为该值不大于O(nlog(n))