202. Happy Number
Problem Description
A happy number is determined through a specific iterative process. Given a positive integer n
, you need to determine whether it's a happy number or not.
The process works as follows:
- Take any positive integer as the starting point
- Calculate the sum of the squares of its digits
- Replace the original number with this sum
- Repeat steps 2-3 continuously
This process leads to one of two outcomes:
- The number eventually reaches 1 and stays there (making it a happy number)
- The number enters an endless cycle that never reaches 1 (making it not a happy number)
For example, if we start with n = 19
:
1² + 9² = 1 + 81 = 82
8² + 2² = 64 + 4 = 68
6² + 8² = 36 + 64 = 100
1² + 0² + 0² = 1 + 0 + 0 = 1
Since we reached 1, the number 19 is happy.
Your task is to implement a function that takes a positive integer n
and returns true
if it's a happy number, or false
otherwise.
The key challenge is detecting when the process enters a cycle (repeats a number we've seen before), which indicates the number will never reach 1 and is therefore not happy.
Intuition
The key insight is recognizing that this process will either converge to 1 or get stuck in a cycle. Since we're repeatedly applying the same transformation (sum of squares of digits), and there are only a finite number of possible results for any given number of digits, we must eventually either reach 1 or revisit a number we've seen before.
Think about it this way: if we have a 3-digit number, the maximum sum of squares we can get is 9² + 9² + 9² = 243
. For any number, the sum of squares of its digits is bounded, which means we're working within a finite space of possible values.
This naturally leads us to the idea of cycle detection. If we keep track of all the numbers we've encountered during the process, we can detect when we've entered a cycle by checking if we've seen the current number before.
The algorithm becomes straightforward:
- Keep a set to store all numbers we've visited
- For each number, calculate the sum of squares of its digits
- If we reach 1, we've found a happy number
- If we encounter a number we've already seen, we've detected a cycle and the number is not happy
- Otherwise, add the current number to our visited set and continue
The use of a set for tracking visited numbers gives us O(1)
lookup time to check if we've entered a cycle, making this approach efficient. The process must terminate because we either reach 1 or detect a cycle within a bounded number of steps.
Solution Approach
The implementation uses a set-based cycle detection approach to determine if a number is happy.
Data Structure Used:
- A
set
calledvis
to track all numbers we've encountered during the process
Algorithm Steps:
-
Initialize tracking: Create an empty set
vis
to store visited numbers. -
Main loop condition: Continue the process while two conditions are met:
- The current number
n
is not equal to 1 - The current number
n
has not been seen before (not invis
)
- The current number
-
Track current number: Add the current
n
to the visited set before processing it. -
Calculate sum of squares of digits:
- Initialize a variable
x = 0
to accumulate the sum - Extract each digit using
divmod(n, 10)
:divmod(n, 10)
returns(quotient, remainder)
where remainder is the last digit- Square the digit (
v * v
) and add tox
- Update
n
to the quotient to process remaining digits
- After processing all digits, update
n = x
for the next iteration
- Initialize a variable
-
Determine result: When the loop exits, check if
n == 1
:- If
n == 1
, the number is happy (returnTrue
) - If loop exited because
n
was invis
, we found a cycle (returnFalse
)
- If
Example walkthrough with n = 19:
- Iteration 1:
n = 19
, extract digits:1² + 9² = 82
- Iteration 2:
n = 82
, extract digits:8² + 2² = 68
- Iteration 3:
n = 68
, extract digits:6² + 8² = 100
- Iteration 4:
n = 100
, extract digits:1² + 0² + 0² = 1
- Loop exits with
n = 1
, returnTrue
The time complexity is O(log n)
for extracting digits, and space complexity is O(k)
where k
is the number of unique numbers encountered before reaching 1 or detecting a cycle.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's trace through the algorithm with n = 2
to see how cycle detection works:
Initial Setup:
vis = {}
(empty set)n = 2
Iteration 1:
- Check:
n != 1
✓ andn not in vis
✓ → Continue - Add
2
tovis
:vis = {2}
- Calculate sum of squares:
2² = 4
- Update:
n = 4
Iteration 2:
- Check:
n != 1
✓ andn not in vis
✓ → Continue - Add
4
tovis
:vis = {2, 4}
- Calculate sum of squares:
4² = 16
- Update:
n = 16
Iteration 3:
- Check:
n != 1
✓ andn not in vis
✓ → Continue - Add
16
tovis
:vis = {2, 4, 16}
- Calculate sum of squares:
1² + 6² = 1 + 36 = 37
- Update:
n = 37
Iteration 4:
- Check:
n != 1
✓ andn not in vis
✓ → Continue - Add
37
tovis
:vis = {2, 4, 16, 37}
- Calculate sum of squares:
3² + 7² = 9 + 49 = 58
- Update:
n = 58
Iteration 5:
- Check:
n != 1
✓ andn not in vis
✓ → Continue - Add
58
tovis
:vis = {2, 4, 16, 37, 58}
- Calculate sum of squares:
5² + 8² = 25 + 64 = 89
- Update:
n = 89
Iteration 6:
- Check:
n != 1
✓ andn not in vis
✓ → Continue - Add
89
tovis
:vis = {2, 4, 16, 37, 58, 89}
- Calculate sum of squares:
8² + 9² = 64 + 81 = 145
- Update:
n = 145
Iteration 7:
- Check:
n != 1
✓ andn not in vis
✓ → Continue - Add
145
tovis
:vis = {2, 4, 16, 37, 58, 89, 145}
- Calculate sum of squares:
1² + 4² + 5² = 1 + 16 + 25 = 42
- Update:
n = 42
Iteration 8:
- Check:
n != 1
✓ andn not in vis
✓ → Continue - Add
42
tovis
:vis = {2, 4, 16, 37, 58, 89, 145, 42}
- Calculate sum of squares:
4² + 2² = 16 + 4 = 20
- Update:
n = 20
Iteration 9:
- Check:
n != 1
✓ andn not in vis
✓ → Continue - Add
20
tovis
:vis = {2, 4, 16, 37, 58, 89, 145, 42, 20}
- Calculate sum of squares:
2² + 0² = 4 + 0 = 4
- Update:
n = 4
Iteration 10:
- Check:
n != 1
✓ butn in vis
✗ (4 is already in our set!) - Loop exits because we detected a cycle
Result: Since n = 4 ≠ 1
, return False
. The number 2 is not happy.
The cycle we detected is: 4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4
(repeats)
Solution Implementation
1class Solution:
2 def isHappy(self, n: int) -> bool:
3 # Set to track visited numbers to detect cycles
4 visited = set()
5
6 # Continue until we reach 1 (happy) or find a cycle (not happy)
7 while n != 1 and n not in visited:
8 # Add current number to visited set
9 visited.add(n)
10
11 # Calculate sum of squares of digits
12 sum_of_squares = 0
13 while n > 0:
14 # Extract last digit using divmod
15 n, digit = divmod(n, 10)
16 # Add square of digit to sum
17 sum_of_squares += digit * digit
18
19 # Update n with the new sum for next iteration
20 n = sum_of_squares
21
22 # Return True if we reached 1, False if we found a cycle
23 return n == 1
24
1class Solution {
2 /**
3 * Determines if a number is a "happy number".
4 * A happy number is defined by the following process:
5 * - Starting with any positive integer, replace the number by the sum of the squares of its digits
6 * - Repeat the process until the number equals 1 (happy) or loops endlessly in a cycle (not happy)
7 *
8 * @param n The positive integer to check
9 * @return true if n is a happy number, false otherwise
10 */
11 public boolean isHappy(int n) {
12 // Set to track visited numbers and detect cycles
13 Set<Integer> visitedNumbers = new HashSet<>();
14
15 // Continue until we reach 1 (happy) or find a cycle (not happy)
16 while (n != 1 && !visitedNumbers.contains(n)) {
17 // Mark current number as visited
18 visitedNumbers.add(n);
19
20 // Calculate sum of squares of digits
21 int sumOfSquares = 0;
22 while (n != 0) {
23 int digit = n % 10; // Extract last digit
24 sumOfSquares += digit * digit; // Add square of digit to sum
25 n /= 10; // Remove last digit
26 }
27
28 // Update n with the new sum for next iteration
29 n = sumOfSquares;
30 }
31
32 // If we exited because n equals 1, it's happy; otherwise, we found a cycle
33 return n == 1;
34 }
35}
36
1class Solution {
2public:
3 bool isHappy(int n) {
4 // Use a hash set to track numbers we've seen to detect cycles
5 unordered_set<int> visitedNumbers;
6
7 // Continue until we either reach 1 (happy number) or find a cycle
8 while (n != 1 && !visitedNumbers.count(n)) {
9 // Mark current number as visited
10 visitedNumbers.insert(n);
11
12 // Calculate the sum of squares of digits
13 int sumOfSquares = 0;
14 while (n > 0) {
15 int digit = n % 10; // Extract the last digit
16 sumOfSquares += digit * digit; // Add square of digit to sum
17 n /= 10; // Remove the last digit
18 }
19
20 // Update n with the new sum for next iteration
21 n = sumOfSquares;
22 }
23
24 // If we exited because n == 1, it's a happy number
25 return n == 1;
26 }
27};
28
1/**
2 * Determines if a number is a "happy number"
3 * A happy number is defined by the following process:
4 * - Starting with any positive integer, replace the number by the sum of the squares of its digits
5 * - Repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle
6 * - Numbers for which this process ends in 1 are happy numbers
7 *
8 * @param n - The number to check
9 * @returns true if n is a happy number, false otherwise
10 */
11function isHappy(n: number): boolean {
12 /**
13 * Calculates the sum of squares of digits for a given number
14 * For example: 19 -> 1^2 + 9^2 = 82
15 *
16 * @param num - The input number
17 * @returns Sum of squares of all digits
18 */
19 const getNext = (num: number): number => {
20 let sumOfSquares: number = 0;
21
22 // Extract each digit and add its square to the sum
23 while (num !== 0) {
24 const digit: number = num % 10;
25 sumOfSquares += digit ** 2;
26 num = Math.floor(num / 10);
27 }
28
29 return sumOfSquares;
30 };
31
32 // Set to track visited numbers and detect cycles
33 const visitedNumbers: Set<number> = new Set<number>();
34
35 // Continue the process until we reach 1 (happy) or find a cycle (not happy)
36 while (n !== 1) {
37 const nextNumber: number = getNext(n);
38
39 // If we've seen this number before, we're in a cycle
40 if (visitedNumbers.has(nextNumber)) {
41 return false;
42 }
43
44 // Track this number as visited
45 visitedNumbers.add(nextNumber);
46
47 // Move to the next number in the sequence
48 n = nextNumber;
49 }
50
51 // We reached 1, so it's a happy number
52 return true;
53}
54
Time and Space Complexity
Time Complexity: O(log n)
The algorithm repeatedly calculates the sum of squares of digits until either reaching 1 or detecting a cycle. For each number processed:
- Extracting digits takes
O(log n)
time (where n is the current number, as it haslog₁₀(n)
digits) - The sequence of numbers will either reach 1 or enter a cycle within
O(log n)
iterations
The key insight is that the sum of squares of digits reduces the number significantly. For a k-digit number, the maximum sum of squares is 9² × k = 81k
. Since k ≈ log₁₀(n)
, the numbers quickly become bounded. Once bounded, the sequence must either reach 1 or cycle within a constant number of steps.
Therefore, the overall time complexity is O(log n)
iterations × O(log n)
per iteration = O(log² n)
, but since the numbers become small quickly after the first few iterations, the amortized complexity is O(log n)
.
Space Complexity: O(log n)
The space is used by the vis
set to store previously seen numbers. In the worst case before detecting a cycle or reaching 1, we store O(log n)
numbers in the set, as the sequence length before cycling is bounded by O(log n)
.
Common Pitfalls
1. Modifying n
while calculating the sum of squares
The Pitfall:
A common mistake is directly modifying n
while simultaneously trying to use it for the sum calculation, leading to incorrect results or infinite loops:
# INCORRECT - modifying n while still needing it
def isHappy(self, n: int) -> bool:
visited = set()
while n != 1 and n not in visited:
visited.add(n)
sum_of_squares = 0
while n > 0:
digit = n % 10
sum_of_squares += digit * digit
n = n // 10 # Problem: n becomes 0 after this loop
# n is now 0, not sum_of_squares!
return n == 1 # Always returns False
The Solution:
Use a separate variable to accumulate the sum, then update n
after the calculation is complete:
# CORRECT - preserve n until calculation is done
sum_of_squares = 0
while n > 0:
n, digit = divmod(n, 10)
sum_of_squares += digit * digit
n = sum_of_squares # Update n after calculation
2. Checking visited set after adding the current number
The Pitfall:
Adding n
to the visited set before checking can cause immediate false cycle detection:
# INCORRECT - adds n before checking
def isHappy(self, n: int) -> bool:
visited = set()
while n != 1:
visited.add(n)
if n in visited: # This will always be True!
return False
# ... rest of code
The Solution:
Check if n
is in the visited set BEFORE adding it:
# CORRECT - check before adding while n != 1 and n not in visited: visited.add(n) # ... rest of code
3. Not handling the initial value of 1
The Pitfall:
If the input n
is already 1, the code might incorrectly add it to visited and process it:
# POTENTIAL ISSUE - unnecessary processing when n=1
def isHappy(self, n: int) -> bool:
visited = set()
while n not in visited: # Missing n != 1 check
visited.add(n)
# ... calculate sum of squares
return n == 1
The Solution:
Include n != 1
in the loop condition to immediately return True for n=1:
# CORRECT - handles n=1 efficiently while n != 1 and n not in visited: # Process only if n is not 1 and not visited
4. Integer overflow concerns (language-specific)
The Pitfall: In languages with fixed integer sizes, squaring large digits repeatedly might cause overflow:
# In Python this isn't an issue, but in C++ or Java: // sum_of_squares += digit * digit; // Could overflow for very large numbers
The Solution: For Python, this isn't a concern due to arbitrary precision integers. For other languages, consider using appropriate data types or adding bounds checking. The maximum sum of squares for any number is bounded (e.g., for a 32-bit integer, the maximum is 9²×10 = 810), so overflow is rarely an actual issue in this problem.
What is the best way of checking if an element exists in an unsorted array once in terms of time complexity? Select the best that applies.
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Tech Interview Pattern Two Pointers Introduction If you prefer videos here's a super quick introduction to Two Pointers div class responsive iframe iframe src https www youtube com embed xZ4AfXHQ1VQ title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture allowfullscreen iframe div Two pointers is a common interview
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Want a Structured Path to Master System Design Too? Don’t Miss This!