Tim Varley Logo
Tim Varley Principal AI Engineer and Tech Leader
Problem #14 medium

Longest Collatz Sequence

The following iterative sequence is defined for the set of positive integers:

  • nn/2n \rightarrow n/2 (nn is even)
  • n3n+1n \rightarrow 3n + 1 (nn is odd)

Using the rule above and starting with 1313, we generate the following sequence:

13402010516842113 \rightarrow 40 \rightarrow 20 \rightarrow 10 \rightarrow 5 \rightarrow 16 \rightarrow 8 \rightarrow 4 \rightarrow 2 \rightarrow 1

It can be seen that this sequence (starting at 1313 and finishing at 11) contains 1010 terms. Although it has not been proved yet (Collatz Problem), it is thought that all starting numbers finish at 11.

Which starting number, under one million, produces the longest chain?

NOTE: Once the chain starts the terms are allowed to go above one million.

View on Project Euler

Implementations

cpp
// https://projecteuler.net/problem=14
// Longest Collatz sequence
// The following iterative sequence is defined for the set of positive integers:
//
// n → n/2 (n is even)
// n → 3n + 1 (n is odd)
//
// Using the rule above and starting with 13, we generate the following sequence:
//
// 13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1
// It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 terms.
// Although it has not been proved yet (Collatz Problem),
// it is thought that all starting numbers finish at 1.
//
// Which starting number, under one million, produces the longest chain?
//
// NOTE: Once the chain starts the terms are allowed to go above one million.
// Answer: 837799
#include <iostream>
#include <vector>
#include <cmath>
#include <cstdint>
uint64_t next_collatz_term(uint64_t prev)
{
uint64_t ret;
if( 0 == (prev%2)){
ret = prev/2;
}else{
ret = (3 * prev)+1;
}
return ret;
}
static std::vector<int> previous_counts(1000000,-1);
int count_collatz_terms_brute(uint64_t start)
{
int count = 1;
while( 1 != start ){
start = next_collatz_term(start);
count++;
}
return count;
}
int count_collatz_terms_opt(uint64_t start)
{
if( 1 == start ) return 1;
int count = 0;
if( start < 1000000 ){
count = previous_counts.at(start);
if( -1 == count ){
count = count_collatz_terms_opt(next_collatz_term(start));
count++;
previous_counts.at(start) = count;
}
}else{
count = count_collatz_terms_brute(start);
}
return count;
}
uint64_t longest_collatz_sequence_brute(uint64_t max_check)
{
int max_count = 0;
int max_counter = 0;
for (uint64_t i = 1; i < max_check; i++) {
int terms = count_collatz_terms_brute(i);
if( max_count < terms ){
max_count = terms;
max_counter = i;
}
}
return max_counter;
}
// Optimization, store previous counts and skip already calculated values.
uint64_t longest_collatz_sequence_opt(uint64_t max_check)
{
int max_count = 0;
int max_counter = 0;
for (uint64_t i = 2; i < max_check; i++) {
if( -1 == previous_counts.at(i) ){
int count = count_collatz_terms_opt(i);
if( max_count < count ){
max_count = count;
max_counter = i;
}
}
}
return max_counter;
}
#if ! defined UNITTEST_MODE
int main(int argc, char const *argv[])
{
std::cout << "Check(1): " << count_collatz_terms_opt(13) << std::endl;
std::cout << "Check(2): " << count_collatz_terms_brute(13) << std::endl;
int answer = longest_collatz_sequence_brute(1000000);
std::cout << "Answer: " << answer
<< '/' << count_collatz_terms_brute(answer)
<< std::endl;
answer = longest_collatz_sequence_opt(1000000);
std::cout << "Answer: " << answer
<< '/' << count_collatz_terms_opt(answer)
<< std::endl;
}
#endif // #if ! defined UNITTEST_MODE
View on GitHub
O(n) time complexity

Solution Notes

Mathematical Background

The Collatz conjecture (also known as the 3n+13n + 1 problem) is an unsolved mathematical problem that asks whether repeating two simple arithmetic operations will eventually transform every positive integer into 1. The operations are:

  • If the number is even, divide it by 2
  • If the number is odd, multiply by 3 and add 1

The sequence length is the count of steps needed to reach 1. For example, starting with 13 produces a 10-term sequence. While the conjecture remains unproven, it has been verified for all starting values up to very large numbers.

Algorithm Analysis

Brute force approach: For each starting number from 1 to 999,999, compute the complete Collatz sequence until reaching 1, counting the steps. This is inefficient as it recomputes sequences for numbers that appear in multiple chains.

Memoization optimization: Store the sequence lengths for each number as they’re computed. When a previously computed number is encountered, reuse its stored length instead of recalculating. This reduces redundant computations significantly.

Space complexity: O(MAX) for the memoization array, where MAX = 1,000,000. Time complexity: O(MAX + total operations), but memoization makes it effectively linear in the number of starting values.

Key Insights

  • The sequence can exceed the starting limit (terms can go above 1,000,000)
  • Memoization prevents recomputing chains for numbers encountered multiple times
  • Most sequences are short, but some starting values produce very long chains
  • The optimal starting number 837,799 produces a chain of 525 terms
  • Performance optimization is crucial due to the large search space

Educational Value

This problem demonstrates:

  • Dynamic programming and memoization techniques
  • The importance of caching intermediate results
  • Trade-offs between time and space complexity
  • Working with sequences and iterative algorithms
  • Handling large search spaces efficiently
  • The Collatz conjecture as an example of an unsolved mathematical problem
  • When optimization matters for computational feasibility