February 19th, 2010

Project Euler Code

My 2010 New Year's resolution is to solve the first 50 problems on Project Euler. I chose to code in Scala for a few reasons: (1) Its functional abilities should lend itself to concise code; (2) It's fast, portable, and easy to execute; and (3) I wanted to build familiarity with a new language. I'm not necessarily going in any specific order, but it makes sense to start with the easy ones first.

Problem One

Add all the natural numbers below one thousand that are multiples of 3 or 5.
0 until 1000 filter(i => {
  (i % 3 == 0) || (i % 5 == 0)
}) reduceLeft { _ + _ }
Reveal code

Problem Two

Find the sum of all the even-valued terms in the Fibonacci sequence which do not exceed four million.
def fib_list(upto:Int) : List[Int] = {
  var l = List(0) 
  var a = 0
  var b = 1
  var c = 0

  for(i <- (0 until upto)) {
    c = a + b
    a = b
    b = c

    l = l ++ List(c)
  }
  l
}

fib_list(32).filter { _ % 2 == 0 } reduceLeft { _ + _ }
Reveal code

Problem Three

Find the largest prime factor of a composite number.
var biggy = BigInt("600851475143")

// would use Math.sqrt, but not avail for BigInt
def cap_search = { biggy / 2 }

def find_next_factor(i:BigInt) : Option[BigInt] = {
  if(i > cap_search) None
  else if(biggy % i == 0) Some(i)
  else find_next_factor(i + 2)  
}

def find_biggest_factor(i:BigInt) : BigInt = {
  find_next_factor(i+2) match {
    case None => biggy
    case Some(x) => {
      biggy /= x
      find_biggest_factor(x)
    }
  }
}

// beginning the search with 3 because
// 1 is a trivial factor and 2 is trivially not
println(find_biggest_factor(3))
Reveal code

Problem Four

Find the largest palindrome made from the product of two 3-digit numbers.
def is_palindrome(x:Int) = {
  // reverse won't return a RichString in scala 2.8 :-)
  x.toString.reverse.toString == x.toString
}

var biggest = 0

for(a <- (100 to 999)) {
  for(b <- (a to 999)) {
    val prod = a * b
    if(is_palindrome(prod))
      biggest = Math.max(biggest, prod)
  }
}

println(biggest)
Reveal code

Problem Five

What is the smallest number divisible by each of the numbers 1 to 20?
var guess:BigInt = 380
var continue = true

def div_by_all(guess:BigInt, r: Range) = r map { guess % _ == 0 } reduceLeft { _ && _ }

while(continue) {
  if(div_by_all(guess, 1 to 20))
    continue = false
  else
    guess += 380
}

println(guess)
Reveal code

Problem Six

What is the difference between the sum of the squares and the square of the sums?
def sq_of_sum(n: Int) { (n*n*n*n + 2*n*n*n + n*n) / 4 }
def sum_of_sq(n: Int) { (0 to n) map { i => i*i } reduceLeft { _+_ } }
println(sq_of_sum(100) - sum_of_sq(100))
Reveal code

Problem Eight

Discover the largest product of five consecutive digits in the 1000-digit number.
val str =  """73167176531330624919225119674426574742355349194934
              96983520312774506326239578318016984801869478851843
              85861560789112949495459501737958331952853208805511
              12540698747158523863050715693290963295227443043557
              66896648950445244523161731856403098711121722383113
              62229893423380308135336276614282806444486645238749
              30358907296290491560440772390713810515859307960866
              70172427121883998797908792274921901699720888093776
              65727333001053367881220235421809751254540594752243
              52584907711670556013604839586446706324415722155397
              53697817977846174064955149290862569321978468622482
              83972241375657056057490261407972968652414535100474
              82166370484403199890008895243450658541227588666881
              16427171479924442928230863465674813919123162824586
              17866458359124566529476545682848912883142607690042
              24219022671055626321111109370544217506941658960408
              07198403850962455444362981230987879927244284909188
              84580156166097919133875499200524063689912560717606
              05886116467109405077541002256983155200055935729725
              71636269561882670428252483600823257530420752963450""".replaceAll("\\s","")

def five_at_a_time(s:String)(block: String => Unit) = {
  for(i <- (0 to str.length - 5))
    block(str.substring(i, i + 5))
}

var biggest = 0

five_at_a_time(str) { substr =>
  val prod = substr.toList.map[Int](x => x.toString.toInt).reduceLeft { _ * _ }
  biggest = Math.max(biggest, prod)
}

println(biggest)
Reveal code

Problem Fourteen

Find the longest sequence using a starting number under one million.
val tops = 1000000
val start = 500000
var biggest = 0

for(i <- start to tops) {

  var last:BigInt = i
  var len = 1

  while(last != 1) {
    last =  if(last % 2 == 0) last / 2 else last*3 + 1
    len += 1
  }

  if(len > biggest) {
    biggest = len
    println(i + " results in length " + len)
  }

  len = 0

}
Reveal code

Problem Sixteen

What is the sum of the digits of the number 2^1000?
var two_exp_k:BigInt = 2
for(i <- 1 until 1000) { two_exp_k = two_exp_k * 2 }
val digit_chars = two_exp_k.toString.toCharArray
val digit_ints = digit_chars.map { _.toString.toInt }
println(digit_ints.reduceLeft{_+_})
Reveal code

Problem Twenty

Find the sum of digits in 100!
def factorial(n: BigInt): BigInt = { if (n == 0) 1 else n * factorial(n-1) }
val digit_chars = factorial(100).toString.toCharArray
val digit_ints = digit_chars.map { _.toString.toInt }
println(digit_ints.reduceLeft{_+_})
Reveal code