Skip to content

4.28.4 — Happy Number

LeetCode 202 · Easy

The problem

Repeatedly replace a number by the sum of the squares of its digits. It is happy if this eventually reaches 1, and unhappy if it loops forever.

19  →  1²+9² = 82  →  8²+2² = 68  →  6²+8² = 100  →  1²+0²+0² = 1   →  true
2   →  4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4 → …               →  false

The pattern

The process is deterministic: each number has exactly one successor. So the sequence either reaches 1 or repeats a value it has already visited — and once it repeats, it is in a cycle forever.

That is 4.9.7 Linked List Cycle with next(n) = the digit-square sum. Any process with a single successor is a linked list, whether or not there are any pointers involved.

Two ways to detect the repeat:

  • A set of everything seen. Simple, O(\log n) space.
  • Floyd's slow and fast pointers. O(1) space, and the reason this problem is filed where it is.

The digit-square step

python
def next_number(n: int) -> int:
    total = 0
    while n:
        n, digit = divmod(n, 10)
        total += digit * digit
    return total

divmod(n, 10) peels the last digit and shifts the rest down in one call. This loop is the standard way to walk a number's digits and it appears in half the problems in this chapter.

The solution

python
class Solution:
    def isHappy(self, n: int) -> bool:
        def next_number(x: int) -> int:
            total = 0
            while x:
                x, digit = divmod(x, 10)
                total += digit * digit
            return total

        slow, fast = n, next_number(n)

        while fast != 1 and slow != fast:
            slow = next_number(slow)
            fast = next_number(next_number(fast))

        return fast == 1
ts
function isHappy(n: number): boolean {
  const next = (x: number): number => {
    let total = 0;
    while (x > 0) {
      const d = x % 10;
      total += d * d;
      x = Math.floor(x / 10);
    }
    return total;
  };

  let slow = n, fast = next(n);

  while (fast !== 1 && slow !== fast) {
    slow = next(slow);
    fast = next(next(fast));
  }

  return fast === 1;
}

The loop ends for one of two reasons, and the return distinguishes them: fast == 1 means happy; slow == fast with fast != 1 means a cycle.

fast starts one step ahead, so the equality test does not fire immediately on the first iteration.

Only fast is checked against 1. It moves faster, so it reaches 1 first if 1 is reachable at all.

The set version

python
def isHappy(self, n):
    seen = set()
    while n != 1 and n not in seen:
        seen.add(n)
        n = next_number(n)
    return n == 1

Shorter, easier to read, O(\log n) space. Write this first, then offer Floyd's when asked about space.

Why the sequence cannot run away to infinity

Worth knowing, because it explains why the problem terminates at all.

For a three-digit number the largest possible digit-square sum is 9^2 \times 3 = 243. For any number with four or more digits the sum is smaller than the number itself — a four-digit number is at least 1,000 while its sum is at most 324.

So every sequence drops below 1,000 within a few steps and stays there. With a finite set of reachable values and a deterministic step, the sequence must eventually repeat. It cannot escape upwards.

In fact every unhappy number falls into the same single cycle: 4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4. So a valid solution is to check whether the sequence ever hits 4. It works, and it relies on a fact you would have to look up — mention it as a curiosity, not as your answer.

Complexity

O(\log n) time for the first step — the number of digits — and then a bounded number of steps, since values quickly fall below 1,000.

O(1) space with Floyd's; O(\log n) with the set.

Where this goes next

The technique — treat a deterministic process as a linked list and use cycle detection — is the transferable part:

  • Linked List Cycle — the original. 4.9.7.
  • Find the Duplicate Number — an array read as a function from index to index. 4.9.8.
  • Pseudorandom number generators — Floyd's is how you measure a generator's period, and a short period is a real defect.
  • Detecting infinite loops in a state machine — the same test.

What the interviewer will push on

"How do you know it terminates?" Values above 1,000 shrink, so the sequence is confined to a finite set and must repeat.

"Why does cycle detection apply?" Each number has exactly one successor, which is a linked list.

"Can you do it in O(1) space?" Floyd's slow and fast.

"Why check only fast against 1?" It moves faster, so it arrives first.

"Is there a shortcut?" Every unhappy number reaches 4. Say it is a looked-up fact rather than a derivation.

One thing to volunteer: say "this is a linked list without pointers" before writing anything. It reframes an arithmetic puzzle as a problem you already solved, which is the whole point of pattern recognition.

Next: 4.28.5 Plus One — the shortest problem in the chapter, with exactly one interesting input.