DEV Community

Alisa Bajramovic
Alisa Bajramovic

Posted on • Edited on

The Happy Number Problem

In this post I'll be walking through the Happy Number Algorithm, a problem recently featured on Leetcode's 30 Day Challenge in April (you can find the problem here).

Here's the question:

Write an algorithm to determine if a number n is "happy".

A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers.

Return True if n is a happy number, and False if not.

For example, let's say your input was 19. The expected output would be true. 19, when broken down into its digits, is 1 and 9. Those numbers squared are 1 and 81. 1 + 81 is 82. 82 broken into its digits is 8 and 2. Those numbers squared are 64 and 4, and 64 + 4 = 68. 68 broken down into its digits is 6 and 8. Those numbers squared is 36 and 64. 36 + 64 = 100. 100 broken down into its digits is 1, 0, and 0. Those numbers squared and summed is 1, which makes it a happy number.

There are a number of ways to approach this problem, and in this post I'll be walking through how to use recursion to solve it.

The first thing I'll do is initialize a variable called sum. The digits of a number will be broken up, set to the power of two, and then added, so it's important to keep track of what the sum is.

function isHappy(n) {
  let sum = 0;
  //...
}
Enter fullscreen mode Exit fullscreen mode

Then, I'll want to break up a number using modulo. As I've explained in a previous blog post, when asked to manipulate a number, it's best to do so without changing it to a string or integer. Modulo enables you do to this easily. If given n = 25, n%10 would give you the result of 5, and n would be 20. Then, we'll want to divide n by 10 in order to shift the digits over. We'll keep doing this as long as n is greater than 0. The other thing to do in this while loop is to add the square of each result of the modulo to the sum. Written out, the function now looks like this:

function isHappy(n) {
  let sum = 0;
  while (n > 0) {
    let e = n % 10;
    n = Math.floor(n / 10);
    sum += e * e;
  }
  //...
}

Enter fullscreen mode Exit fullscreen mode

Now, we need to check what the sum is. If the sum is equal to 1, then it's a happy number, and we can return true.

function isHappy(n) {
  let sum = 0;
  while (n > 0) {
    let e = n % 10;
    n = Math.floor(n / 10);
    sum += e * e;
  }
  if (sum === 1) {
    return true;
  }
  //...

Enter fullscreen mode Exit fullscreen mode

If the sum is greater than 1 but less than or equal to 4, then we know the sum will get stuck in an infinite loop and will never equal 1, so it's definitely not a happy number. You can test this out yourself: if the number is 2, then 2^2 is 4. 4^2 is 16. 1^2 + 6^2 = 37. 3^2 + 7^2 = 58. 5 ^2 + 8^2 = 89. 8^2 + 9^2 = 145. 1^2 + 4^2 + 5+2 = 42. 4^2 + 2^2 = 20. 2^2 + 0^2 = 4 -- and we're stuck in the same loop. (You can also try this out for 3). Therefore, if the sum is greater than 1 and less than or equal to 4, then we can return false.

function isHappy(n) {
  let sum = 0;
  while (n > 0) {
    let e = n % 10;
    n = Math.floor(n / 10);
    sum += e * e;
  }
  if (sum === 1) {
    return true;
  } else if (sum > 1 && sum <= 4) {
    return false;
  }
  //...
}

Enter fullscreen mode Exit fullscreen mode

The final thing to do is make a recursive call to the function. If the sum does not fulfill one of the base cases--it's not equal to 1, 2, 3, or 4--then its digits need to be split, squared, and summed, therefore calling the function again. Therefore, we need to call the function, this time with sum as the argument. It's also important to write 'return' before the function call, or else you'll end up with a result of 'undefined', since nothing was returned back.

function isHappy(n) {
  let sum = 0;
  while (n > 0) {
    let e = n % 10;
    n = Math.floor(n / 10);
    sum += e * e;
  }
  if (sum === 1) {
    return true;
  } else if (sum > 1 && sum <= 4) {
    return false;
  }
  return isHappy(sum);
}

Enter fullscreen mode Exit fullscreen mode

And that's it! Feel free to leave alternate solutions or questions in the comments.

Top comments (9)

Collapse
 
khuongduybui profile image
Duy K. Bui • Edited

Your solution makes sense, mathematically.
However, I think it's a wasted chance to use and explain recursion with carryover.
The function can be something like this:

function isHappy(n, seenSums = []) {
  // ... same as above
  if (sum === 1) return true; // answer found
  if (seenSums.includes(sum)) return false; // generic infinite loop detection mechanism
  return isHappy(sum, seenSums.concat([sum])); // recursion with carryover
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
luispeerez profile image
Luis Perez Bautista

You could use Set instead of an array for seenSums, that way your validation to check the infinite loop could be done in constant time by changing

  if (seenSums.includes(sum)) return false; // generic infinite loop detection mechanism
Enter fullscreen mode Exit fullscreen mode

for

  if (seenSums.has(sum)) return false; // generic infinite loop detection mechanism
Enter fullscreen mode Exit fullscreen mode
Collapse
 
n0vum profile image
Elena Kazakova • Edited

Can you please explain why the solution with new Setdoes not pass in time (Time Limit Exceeded)?
This is OK:
var isHappy = function(n) {
var map = {};
var tmp = 0;
if (n < 1) return false;
while (n !== 1 && !map[n]) {
map[n] = true;
tmp = 0;
while (n > 0) {
tmp += Math.pow(n % 10, 2);
n = Math.floor(n / 10);
}
n = tmp;
}
return n === 1;
};

This is not OK:
var isHappy = function(n) {
function sumSquares(n) {
let sum = 0;
while (n > 0) {
sum += (n % 10) ** 2;
num = Math.floor(n / 10);
}
return sum;
}
const seen = new Set();
while (n != 1 && !seen.has(n)) {
seen.add(n);
n = sumSquares(n);
}
return num == 1;
}

Collapse
 
haideralipunjabi profile image
Haider Ali Punjabi

Why aren't you adding the square of n to the sum?

Collapse
 
alisabaj profile image
Alisa Bajramovic

I'm dividing n into it's digits (so 19 becomes 1 and 9) and then adding the square of those numbers to the sum.

Collapse
 
haideralipunjabi profile image
Haider Ali Punjabi • Edited

Yeah I got that, but I don't see sum += n*n anywhere

Thread Thread
 
alisabaj profile image
Alisa Bajramovic

The line 'sum += e * e' is what sums the digits

Thread Thread
 
haideralipunjabi profile image
Haider Ali Punjabi

Ahh, I missed the while loop there. Oops

Collapse
 
thangtmc73 profile image
Tran Minh Thang

Hi, why a number is not a happy number if the sum is greater than 1 but less than or equal to 4? Why not 5 or 6? Thank you.