2

I am pretty new to solving algorithms so bear with me.

I've solved the Collatz sequence for max length of 1,000,000 but I want to make it more efficient by using a hashtable to look up keys that already exist in order make the function faster. However, I know I'm doing something wrong because it's supposed to take only about 1-2 seconds to run number = 1,000,000, but it's still taking 9-10 seconds to run. I'm pretty new to using hashtables in algorithms so can someone please tell me what I'm doing wrong here in my method?

Much appreciated!

def collatz(n)
  chain = 1
  until n == 1
    n = (n.even?) ? (n/2) : (n*3+1)
    chain += 1
  end
  chain
end

def longest_chain2(number)
  cache = { 1 => 1 }
  start_num = 1
  longest = 1
  while start_num < number
    chain = cache[start_num]
    if chain > longest
      longest = chain
      longest_start = start_num
    end
    start_num += 1
    cache[start_num] = collatz(start_num)
  end
  return longest_start
end

puts longest_chain2(1000000)
iikorni
  • 507
  • 5
  • 16
Lulu Li
  • 83
  • 1
  • 5
  • 3
    Is this algo implemented the correct way? In reality you're not caching anyhting, because `start_num` is increasing by one on each loop, and you never index the hash by anything else than `start_num`. Therefore you will never be looking up old data. I.e. your cache will never experience a "hit". In fact the lookup seems completely unnecessary. – Casper Oct 26 '16 at 20:01
  • I really had to read up on cache and hashes, I don't think I implemented it correctly before at all, and it was taking as long as before because I wasn't calling the cache like you said. Your reply helped me a bunch though in really thinking about which key I'm calling. Thanks! – Lulu Li Oct 27 '16 at 15:57
  • You'll get a big performance boost by using an Array instead of a Hash..... – Bret Weinraub Jun 21 '22 at 17:37

1 Answers1

1

After racking my brain for a whole night, I re-worked the whole thing and wrote out each step every step of the way and realized that my fundamental problem was that I cannot call the collatz method from before (since that method calculates the entire chain, whereas I needed it to stop at the number that I've already calculated). So below is my solution:

def longest_chain2(number)
  cache = { 1 => 1 }
  start_num = 1
  longest = 1
  while start_num < number
    n = start_num
    chain = 0
    while n != 1 && n >= start_num
      if n.even?
        n = n/2
      else
        n = 3*n+1
      end
      chain += 1
    end
    chain += cache[n]
    if chain > longest
      longest = chain
      longest_start = start_num
    end
    cache[start_num] = chain
    start_num += 1
  end
  return longest_start
end

This way, I'll be adding keys that do not already exist, while calling for the value of cache[n] to add to the chain number up to that point.

Lulu Li
  • 83
  • 1
  • 5