Last Updated: March 29, 2026
The core idea is straightforward: take a number, sum the squares of its digits, and repeat. If you eventually hit 1, the number is happy. If you never hit 1, the process will cycle forever, and the number is unhappy.
The tricky part is the second case. How do you know when to stop if the number is NOT happy? You can't just run the process forever. The key observation is that unhappy numbers always enter a cycle. The digit-square-sum of any number below 2^31 quickly shrinks to a small range (the maximum digit-square-sum of a 10-digit number is 9^2 * 10 = 810), so the values are bounded and must eventually repeat. Once a value repeats, you're stuck in an infinite loop.
So the problem reduces to: detect whether the sequence reaches 1 or enters a cycle. This is a classic cycle detection problem.
1 <= n <= 2^31 - 1 → The input can be any positive 32-bit integer. But after one iteration of digit-square-sum, even the largest 10-digit number (2,147,483,647) maps to at most 9^2 * 10 = 810. So the sequence quickly enters the range [1, 810], and cycle detection is efficient.The most natural way to detect a cycle: remember every number you've seen. If the current number is 1, it's happy. If the current number has appeared before, you're stuck in a cycle and it's not happy.
This is the same idea behind detecting cycles in a linked list with a visited set, or detecting infinite loops in any iterative process. You trade space for a simple termination condition.
seen to store numbers we've encountered.n is not 1 and n is not in seen:n to seen.n with the sum of the squares of its digits.true if n equals 1, false otherwise.We detect cycles correctly, but the hash set uses extra memory. Is there a way to detect cycles without storing every visited value?
This is the same insight behind detecting a cycle in a linked list. Instead of storing every number we've seen, we use two pointers: a slow pointer that advances one step at a time, and a fast pointer that advances two steps at a time. If there's a cycle, the fast pointer will eventually catch up to the slow pointer. If the sequence reaches 1, the fast pointer will hit 1 first.
Think of it like two runners on a track. If the track is circular, the faster runner will eventually lap the slower one. If the track has an endpoint (reaching 1), the faster runner gets there first.
The sequence of digit-square-sums forms a chain, just like nodes in a linked list. Each number maps to exactly one next number (the function is deterministic). If the chain reaches 1, it stays at 1 forever (since 1^2 = 1). If it doesn't reach 1, the values are bounded (max 810 for any 32-bit integer), so by the pigeonhole principle, some value must repeat, creating a cycle.
Floyd's algorithm exploits the fact that in any cycle, a pointer moving at double speed will eventually meet a pointer moving at single speed.
slow = n and fast = getNext(n).fast != 1 and slow != fast:slow one step: slow = getNext(slow).fast two steps: fast = getNext(getNext(fast)).true if fast == 1, false otherwise.Both approaches iterate through the sequence, but there's an even simpler observation: every unhappy number eventually reaches the cycle containing 4.
Every unhappy number eventually reaches the cycle 4 -> 16 -> 37 -> 58 -> 89 -> 145 -> 42 -> 20 -> 4. This is the only cycle that exists for this process.
So instead of tracking all visited numbers or running two pointers, we can simply iterate and check: did we reach 1, or did we reach 4? If either happens, we have our answer. This is the simplest code of all three approaches, though it relies on domain-specific knowledge rather than a general algorithm.
n is not 1 and n is not 4:n with the sum of the squares of its digits.true if n equals 1, false otherwise.