Solution: Happy Number
Let's solve the Happy Number problem using the Fast and slow pointers pattern.
Statement
Write an algorithm to determine if a number is a happy number.
We use the following process to check if a given number is a happy number:
- Starting with the given number , replace the number with the sum of the squares of its digits.
- Repeat the process until:
- The number equals , which will depict that the given number is a happy number.
- It enters a cycle, which will depict that the given number is not a happy number.
Return TRUE if is a happy number, and FALSE if not.
Constraints
Solution
So far, you have probably brainstormed some approaches and have an idea of how to solve this problem. Let’s explore some of these approaches and figure out which one to follow based on considerations such as time complexity and any implementation constraints.
Naive approach
The brute force approach is to repeatedly calculate the squared sum of digits of the input number and store the computed sum in a hash set. For every calculation, we check if the sum is already present in the set. If yes, we've detected a cycle and should return FALSE. Otherwise, we add it to our hash set and continue further. If our sum converges to
While this approach works well for small numbers, we might have to perform several computations for larger numbers to get the required result. So, it might get infeasible for such cases. The time complexity of this approach is
Optimized approach using Fast and Slow Pointers pattern
To determine whether a number is a happy number, it is iteratively replaced by the sum of the squares of its digits, forming a sequence of numbers. This sequence either converges to
The pointer moving slower is initialized to the given number, and the faster one starts at the sum of the squared digits of the given number. Then, in each subsequent iteration, the slow pointer updates to the sum of squared digits of itself, while the fast pointer advances two steps ahead: first by updating to the sum of squared digits of itself and then to the sum of squared digits of this recently calculated sum. If the number is happy, the fast pointer will eventually reach
As an example, suppose we have the number
Note: In the following section, we will gradually build the solution. Alternatively, you can skip straight to just the code.
Step-by-step solution construction
We will start off our solution by constructing a helper function to calculate the squared sum of digits of the input number. We know that we need to isolate the digits in our number to calculate the squared sum. This can be achieved by repeatedly removing the last digit of the number and adding its squared value to the total sum.
The helper function will find the last digit of the given number by taking its modulus with . We’ll store this in a variable digit
. Now, since we’ve already separated the last digit, we can get the remaining digits by dividing the number by .
Lastly, we’ll store the squared sum of digit
in a variable named totalSum
. We’ll repeat this until our number becomes .
To understand this better, consider a number, :
First iteration
digit
(last digit)number
(remaining digit(s))totalSum
Second iteration
digit
(last digit)number
(remaining digit(s))totalSum
As the number
has become , we’ll terminate our program here. The squared sum of the digits in is .
class HappyNumber {public static String printStringWithMarkers(String strn, int pValue) {String out = "";for (int i = 0; i < pValue; i++) {out += String.valueOf(strn.charAt(i));}out += "«";out += String.valueOf(strn.charAt(pValue)) + "»";for (int i = pValue + 1; i < strn.length(); i++) {out += String.valueOf(strn.charAt(i));}return out;}public static int sumOfSquaredDigits(int number) {int totalSum = 0;System.out.println("\tCalculating the sum of squared digits");System.out.println("\tTotal sum: " + totalSum);int i = 1;while (number > 0) {System.out.println("\tLoop iteration: " + i);int a = String.valueOf(number).length();System.out.println("\t\tNumber: " + number);int digit = number % 10;System.out.println("\t\tWe will start with the last digit of the number " + digit);System.out.println("\t\t" + printStringWithMarkers(String.valueOf(number), a - 1) + " ⟶ Last Digit: " + digit);System.out.println("\t\tUpdating number ⟶ number/10 = " + number + "/10");number = number / 10;System.out.println("\t\t\t\tThe number is now: " + number);System.out.println("\t\t\tTotal sum + square of the digit = " + totalSum + " + " + digit + " * " + digit + " = " + digit);totalSum += (Math.pow(digit, 2));i = i + 1;}return totalSum;}public static void main(String args[]) {int[] a = {1, 5, 19, 25, 7};for (int i = 0; i < a.length; i++) {System.out.println(i + 1 + "." + "\tInput Number:" + a[i]);System.out.println("\tSum of squared digits: " + sumOfSquaredDigits(a[i]));System.out.println(new String(new char[100]).replace('\0', '-'));}}}
Next, we’ll initialise two variables fast
and slow
with the input number, and the sum of its digits respectively. In each iteration, we’ll move slow
one step forward and fast
two steps forward. That is, we’ll call the sumOfSquaredDigits()
function once for slow
and twice for fast
.
slow
sumOfSquaredDigits(slow)
fast
sumOfSquaredDigits(sumOfSquaredDigits(fast))
If at any instance fast
becomes , we’ve found a happy number. We’ll return TRUE in this case. Otherwise, if fast
becomes equal to slow
, we’ve found a loop and will return FALSE.
class HappyNumber {public static int sumOfSquaredDigits(int number) {int totalSum = 0;while (number > 0) {int digit = number % 10;number = number / 10;totalSum += (Math.pow(digit, 2));}System.out.println("\t\tSum of squared digits: " + totalSum);return totalSum;}public static boolean isHappyNumber(int n) {int slowPointer = n; // The slow pointer valueSystem.out.println("\tSetting slow pointer = input number " + slowPointer);System.out.println("\tSetting fast pointer = sum of squared digits of " + n);int fastPointer = sumOfSquaredDigits(n); // The fast pointer valueSystem.out.println("\tFast pointer:" + fastPointer);while (fastPointer != 1 && slowPointer != fastPointer) { // Terminating conditionSystem.out.println("\n\tRepeatedly updating slow and fast pointers\n");// Incrementing the slow pointer by 1 iterationslowPointer = sumOfSquaredDigits(slowPointer);System.out.println("\tThe updated slow pointer is " + slowPointer);// Incrementing the fast pointer by 2 iterationsfastPointer = sumOfSquaredDigits(sumOfSquaredDigits(fastPointer));System.out.println("\tThe updated fast pointer is " + fastPointer + "\n");}System.out.println("\tIs it a happy number?: " + (fastPointer == 1)); // If 1 is found then it returns True, otherwise Falsereturn fastPointer == 1;}public static void main(String args[]) {int a[] = {1, 5, 19, 25, 7};for (int i = 0; i < a.length; i++) {System.out.println((i + 1) + ".\tInput Number: " + a[i]);isHappyNumber(a[i]);System.out.println(new String(new char[100]).replace('\0', '-'));}}}
Just the code
Here’s the complete solution to this problem:
class HappyNumber {public static int sumOfSquaredDigits(int number) {int totalSum = 0;while (number > 0) {int digit = number % 10;number = number / 10;totalSum += (Math.pow(digit, 2));}return totalSum;}public static boolean isHappyNumber(int n) {int slowPointer = n;int fastPointer = sumOfSquaredDigits(n);while (fastPointer != 1 && slowPointer != fastPointer) {slowPointer = sumOfSquaredDigits(slowPointer);fastPointer = sumOfSquaredDigits(sumOfSquaredDigits(fastPointer));}return fastPointer == 1;}public static void main(String args[]) {int a[] = {1, 5, 19, 25, 7};for (int i = 0; i < a.length; i++) {System.out.println((i + 1) + ".\tInput Number: " + a[i]);String output = isHappyNumber(a[i]) ? "True" : "False";System.out.println("\n\tIs it a happy number? " + output);System.out.println(new String(new char[100]).replace('\0', '-'));}}}
Solution summary
We maintain track of two values using a slow pointer and a fast pointer. The slow runner advances one number at each step, while the fast runner advances two numbers. We detect if there is any cycle by comparing the two values and checking if the fast runner has indeed reached the number one. We return True or False depending on if those conditions are met.
Time complexity
The time complexity for this algorithm is
The worst case time complexity of this algorithm is given by the case of a non-happy number, since it gets stuck in a cycle, whereas a happy number quickly converges to
Before delving into the detailed complexity analysis, let's first consider the largest possible next number for each given number of digits:
Digits | Largest number | Sum of squared digits |
1 | 9 | 81 |
2 | 99 | 162 |
3 | 999 | 243 |
4 | 9999 | 324 |
12 | 999999999999 | 972 |
13 | 9999999999999 | 1053 |
14 | 99999999999999 | 1134 |
To estimate the count of numbers in a cycle, let’s consider the following two cases:
Numbers with three digits: The largest three-digit number is
. The sum of the squares of its digits is . Therefore, for three-digit numbers, no number in the cycle can go beyond . Therefore, the time complexity in this case is given as , where is the maximum count of numbers in a cycle and is the number of digits in a three-digit number. This is why the time complexity in the case of numbers with three digits comes out to be . Numbers with more than three digits: Any number with more than three digits will lose at least one digit at every step until it becomes a three-digit number. For example, the first four-digit number that we can get in the cycle is
, which is the sum of the square of the digits in . Therefore, the time complexity of any number with more than three digits can be expressed as . Since is the dominating term, we can write the time complexity as .
Therefore, the total time complexity comes out to be
Space complexity
The space complexity for this algorithm is
Level up your interview prep. Join Educative to access 70+ hands-on prep courses.