我再一次在我的智慧结束时与Project Euler问题12搏斗。它要求第一个三角形数字超过500个除数。 https://projecteuler.net/problem=12
这是我之前的尝试:
Project Euler 12, Java solution attempt, recursion error?
我收到了许多我努力尝试申请的伟大指示。
感谢您的回复,现在我可以:将素数筛选到一个非常高的值并对任何数字进行素数分解并计算除数。
但我不能将这些技术与找到500除数的三角数的问题联系起来。所以我已经将大量的素数筛选到了大量,然后我该怎么办?我将任何数字分解并计算其除数,然后如何使用它来解决问题?
我回到旧的试用解决方案并清理了代码。现在它可以找到具有低除数的三角形数。但是高达500,编译器继续运行。
这是我清理过的解决方案:
public static void main(String[] args) {
long c=2;
long d=(c*(c+1)/2);
while (numDivs(d)<=500) {
c++;
d=(c*(c+1)/2);
}
System.out.println(d);
System.out.println(c);
}
public static long numDivs(long a) {
long foo=2;
for (long b=1;b*2<=a;b++ ) {
if (a%b==0)
foo++;
}
return foo;
}
有什么方法可以加快这个过程吗?或者我应该放弃这个解决方案?
感谢阅读,我将非常感谢所有的意见。
答案 0 :(得分:0)
我认为,人们可以做的第一件事就是将除数的数量提高两倍,只需减去sqrt
的数量:
public static long numDivs(long a) {
if(a == 1)
return 1;
long num = 2;
int sqrt = (int) Math.sqrt(a);
if(sqrt*sqrt == a) {
num++;
}
for (long b = 2;b < sqrt; b++) {
if (a%b == 0) {
num += 2;
}
}
return num;
}
基本原理:如果dividor大于数字的平方根,它有一个较小的共同数据,而不是单独计算它们,你可以同时计算它们。 / p>
这肯定会产生影响,因为numDivs
现在会有一个时间复杂度 O(sqrt n)而不是 O(n)。
答案 1 :(得分:0)
我认为您尝试应用的算法非常幼稚。
检查我的代码,我认为这样可以更好地使用。
private static List<Integer> sieve(int maxPrime) {
boolean[] isPrime = new boolean[maxPrime];
List<Integer> primes = new ArrayList<>();
Arrays.fill(isPrime, true);
for (int i = 2; i * i < maxPrime; i++) {
if (isPrime[i]) {
primes.add(i);
for (int j = i; i * j < maxPrime; j++) isPrime[i * j] = false;
}
}
return primes;
}
这里我们得到一张地图,其中key是因子,value是它出现的次数。
private static Map<Integer, Integer> factorize(List<Integer> primes, int number) {
Map<Integer, Integer> factors = new HashMap<>();
int tempNumber = number;
for (Integer prime : primes) {
while (tempNumber % prime == 0) {
tempNumber = tempNumber / prime;
if (factors.containsKey(prime)) factors.put(prime, factors.get(prime) + 1);
else factors.put(prime, 1);
}
}
return factors;
}
private static int countDivisors(Map<Integer, Integer> factors) {
int result = 1;
for (Integer c : factors.values()) {
result *= c + 1;
}
return result;
}
public static void main(String[] args) {
final int MAX_PRIME = (int) Math.sqrt(Integer.MAX_VALUE);
List<Integer> primes = sieve(MAX_PRIME);
int triangularNumber = 0;
for (int i = 1; i < Integer.MAX_VALUE; i++) {
triangularNumber += i;
Map<Integer, Integer> factors = factorize(primes, triangularNumber);
int total = countDivisors(factors);
if (total > 500) {
break;
}
}
System.out.println("The number " + triangularNumber);
}
答案 2 :(得分:0)
您不必每次都重新计算三角形数字,只需将c添加为
即可T(n) = T(n-1) + n
所以代码明智
long c=2;
long d=(c*(c+1)/2);
while (numDivs(d)<=500) {
c++;
d += c;
}
应该希望减少所花费的时间