|
| 1 | +#!/usr/bin/env python |
| 2 | + |
| 3 | +""" |
| 4 | +Collatz conjecture: start with any positive integer n. Next term obtained from |
| 5 | +the previous term as follows: |
| 6 | +If the previous term is even, the next term is one half the previous term. |
| 7 | +If the previous term is odd, the next term is 3 times the previous term plus 1. |
| 8 | +The conjecture states the sequence will always reach 1 regardless of starting |
| 9 | +n. |
| 10 | +Problem Statement: |
| 11 | +The following iterative sequence is defined for the set of positive integers: |
| 12 | + n → n/2 (n is even) |
| 13 | + n → 3n + 1 (n is odd) |
| 14 | +Using the rule above and starting with 13, we generate the following sequence: |
| 15 | + 13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1 |
| 16 | +It can be seen that this sequence (starting at 13 and finishing at 1) contains |
| 17 | +10 terms. Although it has not been proved yet (Collatz Problem), it is thought |
| 18 | +that all starting numbers finish at 1. |
| 19 | +Which starting number, under one million, produces the longest chain? |
| 20 | +""" |
| 21 | + |
| 22 | + |
| 23 | +def solution(m): |
| 24 | + """ Returns the number under n that generates the longest Collatz sequence. |
| 25 | +
|
| 26 | + >>> solution(1000000) |
| 27 | + {'counter': 525, 'largest_number': 837799} |
| 28 | + >>> solution(200) |
| 29 | + {'counter': 125, 'largest_number': 171} |
| 30 | + >>> solution(5000) |
| 31 | + {'counter': 238, 'largest_number': 3711} |
| 32 | + >>> solution(15000) |
| 33 | + {'counter': 276, 'largest_number': 13255} |
| 34 | + """ |
| 35 | + # we are going to avoid repeat computations by creating a knowledge base |
| 36 | + # where we store the length of all collatz chains we calculated so far |
| 37 | + |
| 38 | + knowledge = {1: 1} |
| 39 | + |
| 40 | + # a single step in a collatz chain |
| 41 | + def collatz(n): |
| 42 | + if n % 2 == 0: |
| 43 | + return n // 2 |
| 44 | + else: |
| 45 | + return 3 * n + 1 |
| 46 | + |
| 47 | + # calculates a collatz chain of a certain number this calculation is halted |
| 48 | + # whenever we find a key with a know collatz chain in our knowledge base |
| 49 | + def calculateChain(n): |
| 50 | + entries = [] |
| 51 | + while n not in knowledge: |
| 52 | + entries.append(n) |
| 53 | + n = collatz(n) |
| 54 | + chainSize = knowledge[n] |
| 55 | + for i in entries[::-1]: |
| 56 | + chainSize += 1 |
| 57 | + knowledge[i] = chainSize |
| 58 | + |
| 59 | + maxChain = { |
| 60 | + "counter": 1, |
| 61 | + "largest_number": 1 |
| 62 | + } |
| 63 | + for i in range(1, m + 1): |
| 64 | + calculateChain(i) |
| 65 | + if maxChain["counter"] < knowledge[i]: |
| 66 | + maxChain = { |
| 67 | + "counter": knowledge[i], |
| 68 | + "largest_number": i |
| 69 | + } |
| 70 | + |
| 71 | + return maxChain |
| 72 | + |
| 73 | + |
| 74 | +if __name__ == "__main__": |
| 75 | + print("calculate the number with the longest collatz chain in the range between 1 and the following number:") |
| 76 | + inputNumber = int(input().strip()) |
| 77 | + number, chainLength = solution(inputNumber) |
| 78 | + print(f"the maximum collatz chain of all numbers between 1 and {inputNumber} is {chainLength}, starting with the number {number}") |
| 79 | + |
0 commit comments