题目:
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 true ;不是,则返回 false 。
示例:
输入:19
输出:true
解释:
1
2
+
9
2
=
82
1^2 + 9^2 = 82
12+92=82
8
2
+
2
2
=
68
8^2 + 2^2 = 68
82+22=68
6
2
+
8
2
=
100
6^2 + 8^2 = 100
62+82=100
1
2
+
0
2
+
0
2
=
1
1^2 + 0^2 + 0^2 = 1
12+02+02=1
思路:
方法1,哈希表,首先判断几种情况,按照题目中的计算方法,如果得到1,就是快乐数,还有可能就是到达某个数的时候无限循环,这个值不可能无穷大,因为当这个值为999 的时候,下一个就是243,也就是说三位数的时候,当前数最大情况下的下一个数,最大就是243了,如果是四位数或者四位数以上的数,那在后面的运算中也会降低到3位,所以不会是无穷。
所以最后就是要么1,快乐数,要么循环。
建立一个字典,先把当前数放在字典中,然后计算下一个数,如果下一个数不在字典中就放进去,表示没有出现过,现在标记了,如果在字典中,说明循环了,已经出现过了,返回false,如果下一个数是1直接返回true。计算下一个数的计算过程是累加当前数除以10后的余数,再将当前数地板除以10,使得下一次取前一位。
时间复杂度的开销在计算下一个数,计算下一个数主要看下一个数的位数,下一个数的位数和当前数的关系是对数关系,所以时间复杂度是O(logN)。
方法2,快慢指针
两种情况,要么1,要么循环,设置快慢指针都来表示下一个数,慢指针一个一个走,快指针的返回值两个两个走,初始慢指针指向当前数,快指针指向当前数的下一个数,如果是快乐数,那快指针肯定先到达1,就可以跳出循环返回,如果不是快乐数,那就会进入循环,快指针和慢指针肯定会相遇,并且慢的是第一次到,快的是第二次到,跳出循环返回false即可。
class Solution(object):
def isHappy(self, n):
"""
:type n: int
:rtype: bool
"""
# 用哈希表字典,不用其他数据结构是因为计算时间复杂度较高
# res = {}
# while n!= 1 and n not in res:
# res[n] = 1
# cur_sum = 0
# while n > 0:
# cur_sum += (n % 10)*(n % 10)
# n //= 10
# n = cur_sum
# return n == 1
# 三种情况,要么回到1,要么到达某个数再无限循环,不可能到达无穷大。时间和空间复杂度分析,logN
# 快慢指针的方法
def get_next(num):
cur_sum = 0
while num > 0:
cur_sum += (num % 10)*(num % 10)
num //= 10
return cur_sum
slow = n
fast = get_next(n)
while fast != 1 and slow != fast:
slow = get_next(slow)
fast = get_next(get_next(fast))
return fast == 1