Leetcode 202 question: two solutions to Happy Number

Keywords: Algorithm data structure leetcode linked list HashMap

Title Description

Determines whether a number n is a happy number. The definition of happy number is as follows:

Starting with any positive integer, replace the number by the sum of the squares of its digits.
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.

It means constantly replacing the original n with the square sum of the numbers in each bit of N. if it can finally return to 1, then this number is happy number. If it finally falls into a cycle, excluding 1, then this number is not happy number.

After reading the title, I have a doubt. Is there no third situation except returning to 1 and falling into cycle? Won't the situation of infinite non circulation become bigger and bigger? But in fact, after careful thinking, you will find that this is impossible. For example, if the original n is the maximum value of 9999 in the 4 digits, then its next iteration value is nothing more than 9 ^ 2 * 4 = 324. Even if we start with 9999, in the next steps, n can only wander in the range below 324, then it will eventually fall into the cycle after 324 iterations at best. The logic of other digits is the same, That is, the case of infinite increase is impossible. So the only possible scenario is to fall into a loop that does not contain 1, or go back to 1.

Solution 1: Hash

After understanding this problem, we can start thinking about how to solve it. My idea is to use hashmap. Keep cycling and save the existing n in a table. If the next value exists in the storage table (use hash to index), and 1 does not appear at this time, it means that this 1 will never appear again. This value must not be happy. The code is as follows

class Solution(object):
    def isHappy(self, n):
        """
        :type n: int
        :rtype: bool
        """
        n_history={}
        while True:
            try:
                n_history[n]+=1
                return False
            except:
                n_history[n]=0
                digit_li=[str(n)[i] for i in range(len(str(n)))]
                n=sum(list(map(lambda x:(int(x))**2,digit_li)))
                if n==1:
                    return True

The following is the first official solution. The general idea is actually the same.

def isHappy(self, n: int) -> bool:

    def get_next(n):
        total_sum = 0
        while n > 0:
            n, digit = divmod(n, 10)
            total_sum += digit ** 2
        return total_sum

    seen = set()
    while n != 1 and n not in seen:
        seen.add(n)
        n = get_next(n)

    return n == 1

Solution 2: Floyd's cycle finding algorithm

To put it simply, we set two variables, a fast_runner, two steps at a time, and a slow_runner, one step at a time. As mentioned above, the process of this iteration has only two results, falling into cycle or returning to 1. If it can finally return to 1, it must be arrived by fast_runner. If it falls into cycle, fast_runner and slow_runner will meet. Either When the situation occurs, we let the loop terminate. Next, we only need to judge the situation of fast_runner at the time of termination. If it is 1, it is happy number, otherwise it is not. The code is as follows:

def isHappy(self, n: int) -> bool:  
    def get_next(number):
        total_sum = 0
        while number > 0:
            number, digit = divmod(number, 10)
            total_sum += digit ** 2
        return total_sum

    slow_runner = n
    fast_runner = get_next(n)
    while fast_runner != 1 and slow_runner != fast_runner:
        slow_runner = get_next(slow_runner)
        fast_runner = get_next(get_next(fast_runner))
    return fast_runner == 1

Posted by redrabbit on Sat, 20 Nov 2021 21:35:38 -0800