DynamicFaster thanks to the help of dynamic programming approach:, at the cost of some extra memory usage. We save the lengths of each chain we calculate, and reuse them so we only need to calculate them once. This implementation only saves lengths for values below the number we're going up to, but since the collatz function will go above this, we could raise the range of values we save if we don't mind increasing space used
def k(upto):
def collatz(n):
if n < upto and lst[n] > 0:
return lst[n]
if n % 2 == 0:
val = collatz(n/2) + 1
else:
val = collatz((3*n + 1)/2) + 2
if n < upto:
lst[n] = val
return val
lst = [0]*upto
lst[1] = 1
lst[0] = 1
for i in range(upto):
collatz(i)
return max(lst)