Saturday, May 19, 2012

Project Euler is awesome, part 2

Project Euler is cool,  awesome. Solutions to the problems force me to come with efficient algorithms.

Here is Problem # 12:

The sequence of triangle numbers is generated by adding the natural numbers. So the 7th triangle number would be 1 + 2 + 3 + 4 + 5 + 6 + 7 = 28. The first ten terms would be:

1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...

Let us list the factors of the first seven triangle numbers:

 1: 1
 3: 1,3
 6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28
We can see that 28 is the first triangle number to have over five divisors.

What is the value of the first triangle number to have over five hundred divisors?

Here is the Java solution to this problem:

public class Problem012 {
 
 static private long findPrimeFactors(long number, Long[] primelist) {
     int numOfFactors = 1;
     int exponent;
     long remain = number;
  
     for (int i = 0; i < primelist.length; i++) {
         if (primelist[i] * primelist[i] > number) {
             return numOfFactors * 2;
         }
  
         exponent = 1;
         while (remain % primelist[i] == 0) {
             exponent++;
             remain = remain / primelist[i];
         }
         numOfFactors *= exponent;
  
         //If there is no remainder, return the count
         if (remain == 1) {
             return numOfFactors;
         }
     }
     return numOfFactors;
 }
 
 
 public static void findNumber(int count) { 
  
  long startTime = System.nanoTime();
  
  long number = 1;
  long i = 2;
  long cnt = 0;
  long factorCount1 = 2;
  long factorCount2 = 2;
  
  Long[] primes = runEratosthenesSieve(1000);
  
  while (cnt < count) {
   if (i % 2 == 0) {
    factorCount2 = findPrimeFactors(i + 1, primes);
    cnt = factorCount2 * factorCount1;
   } else {
    factorCount1 = findPrimeFactors((i + 1) / 2, primes);
    cnt = factorCount2*factorCount1;
   }
   i++;
  }
  number = i * (i - 1) / 2;
  long elapsedTime = (System.nanoTime() - startTime) / 1000000; // ms
  
  System.out.println("The number with five hundred divisors is " + number + " time took to find it : " + elapsedTime + " ms");
 }
 
 
 public static void findNumberV2(int count) { 
  
  long startTime = System.nanoTime();
  
  long number = 1;
  long i = 2;
  long cnt = 0;
  
  Long[] primes = runEratosthenesSieve(1000);
  
  while (cnt < count) {
   number += i++;
   cnt = findPrimeFactors(number, primes);
  }

  long elapsedTime = (System.nanoTime() - startTime) / 1000000; // ms
  
  System.out.println("The number with five hundred divisors is " + number + " time took to find it : " + elapsedTime + " ms");
 }

 static public Long[] runEratosthenesSieve(int upperBound) {
  ArrayList<Long> listPrim = new ArrayList<Long> ();
  
  int upperBoundSquareRoot = (int) Math.sqrt(upperBound);
  boolean[] isComposite = new boolean[upperBound + 1];
  for (int m = 2; m <= upperBoundSquareRoot; m++) {
   if (!isComposite[m]) {
            //System.out.print(m + " ");
    listPrim.add(new Long(m));
    for (int k = m * m; k <= upperBound; k += m)
             isComposite[k] = true;
   }
  }
     
  for (int m = upperBoundSquareRoot; m <= upperBound; m++) {
   if (!isComposite[m]) {
    listPrim.add(new Long(m));
   }
  }
  return listPrim.toArray(new Long[listPrim.size()]) ;
 }


 

 public static void main(String[] args) { 

  findNumber(500);
  findNumberV2(500);
 }
}




When you run the code, you will find out the method findNumber() is more efficient than findNumberV2()

No comments:

Post a Comment