我需要计算
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
次。
答案 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))
。