我正在研究Project Euler的问题#12,其内容如下:
通过添加自然数来生成三角数的序列。所以第7个三角形数字是1 + 2 + 3 + 4 + 5 + 6 + 7 = 28.前十个术语是:
1,3,6,10,15,21,28,36,45,55,......
让我们列出前七个三角形数字的因子:
1:1
3:1,3
6:1,2,3,6
10:1,2,5,10
15:1,3,5,1521:1,3,7,21
28:1,2,4,7,14,28
我们可以看到28是第一个超过五个除数的三角形数。
第一个三角形数的值超过500个除数是多少?
这是我到目前为止的代码,但是控制台在运行时不会返回任何内容:
public class Euler12 {
public static void main (String[] args) {
int i = 1;
int x = 2;
boolean found = false;
while (!found) {
if (divisors(i) > 500) {
System.out.println(i);
found = true;
}
else {
i +=x;
x++;
}
}
}
public static int divisors (int n) {
int counter = 0;
for (int i = 1; i <= n; i++) {
if (n % i == 0) counter++;
}
return counter;
}
}
答案 0 :(得分:2)
运行程序后,似乎它的运行时间非常长,看着你的算法,它确实(我以前做过这个问题)。你需要优化“除数”
<强> SPOILER 强>
如果将(int i = 1; i&lt; = n; i ++)更改为for(int i = 1; i * i&lt; = n; i ++),则会大大减少执行时间。
更新: 在没有改变的情况下运行后,在4分钟内没有答案,这违反了Project Euler的一分钟规则。改变后,在十秒钟内得到答案。享受:)
答案 1 :(得分:1)
public class EulerProb12 {
public static void main(String[] args) {
int fib=0, count =1, i=1, incr=0;
while (incr<5){
fib=0;
while (i<=count){
fib = fib+i;
i++;
}
i=1;
incr=0;
count++;
for(int j=1; j<= Math.sqrt(fib); j++ ) // I used fib/2 here n result came late.
{
if(fib%j==0)
{
incr++;
}
}
incr*=2; // New logic when implemented along with sqrt
// if(incr>150)
System.out.println("Number: " + fib + " | Total Divisors: " + incr); }
System.out.println("Number: " + fib + " | Total Divisors: " + incr);
}
}
答案 2 :(得分:1)
以下是两种选择:
1)迭代所有三角形,如果currentSum
(三角形数字)超过THRESHOLD
除数则停止
时间:1.79秒。
public class P12 {
final static int THRESHOLD = 500;
public static void main(String[] args) {
System.out.println(getTriangle());
}
public static long getTriangle() {
int n = 1;
long currentSum = 0;
while (!hasOverXDivisors(currentSum, THRESHOLD)) {
currentSum += n;
n++;
}
return currentSum;
}
private static boolean hasOverXDivisors(long nr, int threshold) {
if ( nr <= threshold ) {
return false;
}
int divisors = 0;
int i;
int sqrt = (int) Math.sqrt(nr);
for ( i = 1 ; i <= sqrt ; i++ ) {
if ( nr % i == 0 ) {
divisors+=2; // E.g.: (2, n/2), (3, n/3)
}
}
if ( sqrt*sqrt == nr ){ // it was counted twice
divisors--;
}
if ( divisors > threshold ) {
return true;
}
return false;
}
}
2)它基于互质数字属性。三角形数等于n*(n+1)/2
,其中n
和n+1
是互质= = n
和(n+1)/2
是互质,n/2
和n+1
是互质(取决于n
是偶数还是奇数)。
时间:61毫秒。
public class P12 {
final static int THRESHOLD_DIVISORS = 500;
public static void main(String[] args) {
System.out.println(getTriangle(1));
}
public static long getTriangle(int n) {
long numberOfDivisors = 0;
long firstCoprime, secondCoprime;
while (true) {
if ( n % 2 == 0 ) {
firstCoprime = getNumberOfDivisors(n/2);
secondCoprime = getNumberOfDivisors(n+1);
} else {
firstCoprime = getNumberOfDivisors(n);
secondCoprime = getNumberOfDivisors((n+1)/2);
}
numberOfDivisors = firstCoprime * secondCoprime;
if ( numberOfDivisors > THRESHOLD_DIVISORS ) {
return n*(n+1)/2;
}
n++;
}
}
private static long getNumberOfDivisors(long nr) {
int divisors = 0;
int i;
int sqrt = (int) Math.sqrt(nr);
for ( i = 1 ; i <= sqrt ; i++ ) {
if ( nr % i == 0 ) {
divisors+=2; // E.g.: (2, n/2), (3, n/3)
}
}
if ( sqrt*sqrt == nr ){ // it was counted twice
divisors--;
}
return divisors;
}
}
我使用整数作为getTriangle()
方法的参数来更容易地改进此方法。对于此特定情况,您可以决定从大于1
的值开始。在这种情况下,您可以将时间减少至少3次。
答案 3 :(得分:0)
使用“素数因子分解”将使您的divisor()
更快更好。
尝试使用以下功能getNumberOfDivisors()
,而不是divisor()
。
public static long getNumberOfDivisors (long n) {
int ret = 1;
long factor = 2;
while (factor <= n) {
int temp = 1;
while (n % factor == 0) {
n /= factor;
temp++;
}
ret *= temp;
factor++;
}
return ret;
}
该函数的工作原理如下:
如果n = p 1 e1 p 2 e2 ... p n en ,其中n是一个整数,p i :primes,
然后,
正向除数:( e 1 + 1)(e 2 + 1)...(e n + 1)