202、快乐数
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 True ;不是,则返回 False 。
输入:19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
**解答:**首先考虑暴力法,即利用一个函数求取数字的各为平方和,然后用该结果直接递归,判定最终结果是否为1。结果显而易见,必会超时,大概率因此数字的平方和陷入了一个环中。
对题目进行分析总结,数字的平方和具有以下特征:
1、1的平方和一直为1,等同于一个只有元素1的环。
2、1位数的最大平方和位81;2位数的最大平方和位:162;三位数的最大平方和为:24;4位数的最大平方和为:324;5位数的最大平方和为:405; 32位数的最大平方和为:32*81=2592。而大于4为数的平方和再进行一轮平方和必然会损失一位数,一直降到3位数以下。
因此:一个数进行一直平方和只有两种结果:1)陷入为1的环,即返回True;2)陷入一个不含1的环,然后一直在环中循环。
针对上述结论:解题思路有:1)利用set集合保存已经出现过的n,当再次出现n时推出循环,并判断n是否为1。2)利用链表中解决有环的方法,采用快慢指针进行解决。循环终止条件为:
def isHappy(self, n: int) -> bool:
def get_square_add(n):
count = 0
while n>0:
count += (n%10)**2
n //= 10#特别注意。python //表示整数,是一个整数。 /是直除,是一个浮点数。使用/会一直循环。
return count
# solution1:利用set进行是否有环。
# seen = set()
# while n !=1 and n not in seen:
# seen.add(n)
# n = get_square_add(n)
# return n==1
# solution2、 利用快慢指针判断是否有环
slow = n
fast = get_square_add(n) #注意不能初始化也为n,不然会直接slow==fast,进不去循环
while slow !=fast and fast != 1: #由于1的平方和还为1,因此只需要判断是否fast为1即可,如果要先到达,肯定是fast先。或者干脆不用判断即可。因此最终会落入到1的环中。
slow = get_square_add(slow)
fast = get_square_add(get_square_add(fast))
return fast ==1
**易错点:**1)求各平方和时:python //表示整数,是一个整数。 /是直除,是一个浮点数。由于小数的原因,使用/会一直循环。
2)快慢指针循环终止条件:可以为while slow !=fast and fast != 1 and slow!=1。但是鉴于如果有1,则会进入1的循环,且不会跳出。因此可直接判断fast这个快指针即可。或者两者都不用判断,最后循环结束时判断其中一个是否为1即可。
3)slow和fast的初始化一个为n,一个为get(n)。如果都设置为n,则会直接跳出循环。
上述求了一个数的各位平方和,下面求一个数的各位和的方法
258. 各位相加
给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。
输入: 38
输出: 2
解释: 各位相加的过程为:3 + 8 = 11, 1 + 1 = 2。 由于 2 是一位数,所以返回 2。
进阶:
你可以不使用循环或者递归,且在 O(1) 时间复杂度内解决这个问题吗?
理解: 一个3位数可表示未:x100+10y+z =99x+9y+x+y+z。因此,求x100+10y+z的系数之和即x+y+z等同于针对99x+9y+x+y+z求x+y+z;那么可以99x+9y+x+y+z对9求余,即得x+y+z,此时x+y+z必然小于9,不需要再求各位之和了。同时:为了避免为9时得为0,采用(a-1)%9+1的方式对9求余。
def addDigits(self, num: int) -> int:
if num ==0:
return 0
#1、直观想法,使用递归暴力破解
# if num<10:
# return num
# #求取数字的各位之和
# sum =0
# sum += while(...)
# addDigits(sum)
#2、数学推导的方法
# x*100+10*y+z =99*x+9*y+x+y+z。因此,求x*100+10*y+z的系数之和即x+y+z等同于针对99*x+9*y+x+y+z求x+y+z
#那么可以99*x+9*y+x+y+z对9求余,即得x+y+z。为了避免为9时得为0,采用(a-1)%9+1的方式对9求余
return (num-1)%9+1