Back to problems
#202Easy·hash-set·3 min read

Non-Cyclical Number

hash-tablemathtwo-pointers
Share

This problem, commonly known as the Happy Number problem, is a classic cycle-detection challenge. In NeetCode, it is referred to as the Non-Cyclical Number problem.

The Problem Explained

A number is "non-cyclical" if, by repeatedly replacing it with the sum of the squares of its digits, you eventually reach the number 1. If you get stuck in a loop (a cycle) that never reaches 1, the number is cyclical (unhappy).

Example: 19

  1. 12+92=1+81=821^2 + 9^2 = 1 + 81 = 82
  2. 82+22=64+4=688^2 + 2^2 = 64 + 4 = 68
  3. 62+82=36+64=1006^2 + 8^2 = 36 + 64 = 100
  4. 12+02+02=11^2 + 0^2 + 0^2 = 1 (Stops at 1 → True)

Step 1: Creating the Helper Function

Before solving the main logic, we need a way to calculate the "sum of squares of digits."

In JavaScript, we can do this mathematically using the modulo operator (%) and Math.floor(). This is more efficient than converting the number to a string.

function getSumOfSquares(n) {
    let sum = 0;
    while (n > 0) {
        let digit = n % 10;   // Get the last digit (e.g., 19 % 10 = 9)
        sum += digit * digit; // Square it and add to sum
        n = Math.floor(n / 10); // Remove the last digit (e.g., 1.9 becomes 1)
    }
    return sum;
}

Step 2: The Logic (Using a Hash Set)

To know if we are in an infinite loop, we need to keep track of every number we've already seen. If we see a number for the second time, we know we are stuck in a cycle.

The Strategy:

  1. Create a Set to store visited numbers.
  2. While the current number is not 1:
    • Check if the number is already in the Set. If yes, return false (cycle detected).
    • If not, add the number to the Set.
    • Calculate the next number using our helper function.
  3. If the loop ends because the number became 1, return true.

Step 3: The Complete JavaScript Solution

/**
 * @param {number} n
 * @return {boolean}
 */
var isHappy = function(n) {
    const seen = new Set();
 
    // Keep going until n is 1 (success) or we hit a number we've seen before (fail)
    while (n !== 1 && !seen.has(n)) {
        seen.add(n);
        n = getSumOfSquares(n);
    }
 
    // If the loop stopped because n is 1, return true. Otherwise, false.
    return n === 1;
};
 
function getSumOfSquares(num) {
    let output = 0;
    while (num > 0) {
        let digit = num % 10;
        output += digit * digit;
        num = Math.floor(num / 10);
    }
    return output;
}

Why does this work? (Understanding the Constraints)

You might wonder: Could the numbers just keep getting bigger forever? Actually, no. For any number with many digits, the sum of the squares of its digits will eventually shrink down into a smaller range (usually under 243 for 3-digit numbers). Once the numbers are in that small range, they must either hit 1 or start repeating. Because the space of possible numbers is limited, a Set is a perfect tool to catch those repeats.

Alternative: Floyd's Cycle-Finding Algorithm

If you want to be extra fancy (and save memory), you can use the "Fast and Slow Pointer" approach (Tortoise and Hare).

  • The Slow pointer calculates the next sum once.
  • The Fast pointer calculates the next sum twice.
  • If they ever meet at the same number (other than 1), there is a cycle!

This approach uses O(1)O(1) space because you don't need a Set to store every number you've seen.

Happy Number - Leetcode 202 - Python Neetcode

This video provides a visual walkthrough of the cycle detection logic using both a Hash Set and the more advanced Fast and Slow pointers.

You might also like