File: happy-number/solution.py

Date: 2026-06-06

Time: 16:59

Purpose

This file solves LeetCode #202 — Happy Number. It determines whether a number is "happy" by repeatedly replacing it with the sum of the squares of its digits, checking if the sequence eventually reaches 1 (happy) or enters a cycle (not happy). It uses Floyd's cycle detection (tortoise and hare) instead of a hash set, giving O(1) space.

Key Components

get_next(n: int) -> int

Computes the digit-square-sum of n. Extracts digits via repeated divmod(n, 10), accumulates digit * digit. This is the "step function" that defines the sequence — every call advances one position in the chain n → sumofsquares(n) → ....

is_happy(n: int) -> bool

The main solver. Initializes a slow pointer at n and a fast pointer one step ahead at get_next(n). Advances slow by one step and fast by two steps per iteration until either:

Returns fast == 1 after the loop exits.

Patterns

Floyd's cycle detection — the classic tortoise-and-hare approach. The problem's structure guarantees every sequence either terminates at 1 (which maps to itself: get_next(1) == 1, a fixed point) or enters a finite cycle. Floyd's algorithm detects both in O(1) space, avoiding the unbounded growth of a seen set.

Functional decomposition — the step function getnext is separated from the cycle-detection logic in ishappy. This keeps each function single-purpose and makes get_next independently testable.

Dependencies

Imports: None — pure Python, no standard library or third-party dependencies.

Imported by: happy-number/test_solution.py (directly). The massive "Imported By" list in the prompt is an artifact of the test harness structure — those other test files don't actually import this module; they share a common test runner pattern.

Flow

1. is_happy(n) is called with a positive integer.

2. slow = n, fast = get_next(n) — fast starts one step ahead.

3. Loop: while fast != 1 (not happy yet) and slow != fast (no cycle yet):

4. Loop exits. If fast == 1, the number is happy. If slow == fast (and fast != 1), a cycle was found — not happy.

For n = 19: the sequence is 19 → 82 → 68 → 100 → 1. Fast reaches 1 before slow catches it.

For n = 2: the sequence enters the cycle 2 → 4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4 → ... and the pointers eventually collide.

Invariants

Error Handling

None. The functions assume valid input and contain no guards, assertions, or exception handling. Passing 0 would cause getnext to return 0 (the while loop body never executes), and ishappy(0) would spin forever since fast would be 0 (never 1) and slow would immediately equal fast — actually it would return False on the first check since slow = 0 and fast = get_next(0) = 0, so slow == fast is true and fast != 1, exiting with False. Negative numbers would loop indefinitely due to divmod behavior with negatives producing negative remainders.

Topics to Explore

Beliefs