(day27)

目录

🖍题目:

题目分析:

解题思路:

✨解法一(规律总结)

🌈代码实现

🌟代码注释

✨解法二(递归直观解法)

🌈代码实现

🌟代码注释


🖍题目:

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

  • 1 <= n <= 231 - 1

🌠示例 1:

输入:n = 19

输出:true

说明:

六一儿童节快乐代码Python python编程题快乐数_快乐数

+

六一儿童节快乐代码Python python编程题快乐数_字符串转数值_02

 = 82(第一次判断)

六一儿童节快乐代码Python python编程题快乐数_力扣_03

 +

六一儿童节快乐代码Python python编程题快乐数_快乐数_04

 = 68(第二次判断,下面的一次类推为第几次判断)

六一儿童节快乐代码Python python编程题快乐数_快乐数_05

 +

六一儿童节快乐代码Python python编程题快乐数_力扣_03

 = 100

六一儿童节快乐代码Python python编程题快乐数_快乐数

 +

六一儿童节快乐代码Python python编程题快乐数_快乐数_08

 +

六一儿童节快乐代码Python python编程题快乐数_快乐数_08

 = 1

🌠示例 2:

输入:n = 2

六一儿童节快乐代码Python python编程题快乐数_快乐数_04

 = 4

六一儿童节快乐代码Python python编程题快乐数_python_11

 = 16

六一儿童节快乐代码Python python编程题快乐数_快乐数

 +  

六一儿童节快乐代码Python python编程题快乐数_快乐数_05

 = 37

六一儿童节快乐代码Python python编程题快乐数_力扣_14

 + 

六一儿童节快乐代码Python python编程题快乐数_快乐数_15

 = 58

六一儿童节快乐代码Python python编程题快乐数_python_16

 + 

六一儿童节快乐代码Python python编程题快乐数_力扣_03

 = 89

六一儿童节快乐代码Python python编程题快乐数_力扣_03

 + 

六一儿童节快乐代码Python python编程题快乐数_字符串转数值_02

 = 145

 

六一儿童节快乐代码Python python编程题快乐数_快乐数

 + 

六一儿童节快乐代码Python python编程题快乐数_python_11

 + 

六一儿童节快乐代码Python python编程题快乐数_python_16

 = 42

 

六一儿童节快乐代码Python python编程题快乐数_python_11

 + 

六一儿童节快乐代码Python python编程题快乐数_快乐数_04

 = 20

六一儿童节快乐代码Python python编程题快乐数_快乐数_04

 +  

六一儿童节快乐代码Python python编程题快乐数_快乐数_08

 = 4

标记的这两部构成一个循环,所以2不是快乐数

输出:false

题目分析:

题目的要求就是判断所给的数是否符合“快乐数”的定义,这与水仙花数和回文数类似。都是判断所给的数据是否符合某种定义。

解题思路:

✨解法一(规律总结)

对于快乐数的定义,可经过有限的列举发现其中的规律。

那么我们有

所有不快乐数的数位平方和计算,最後都会进入 4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4 的循环中。

对此,当我们按照定义对快乐数进行判断时,只要再某一平方和计算后出现(4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4 )中的某一数字则会进入循环,那么即可判断这个数不是快乐数。

那么我们现在分析如何实现按定义进行平方和。

以n = 19为例,由定义每一次将该数替换为它每个位置上的数字的平方和

对此我们可以将n除于10后求余(取余符号%),那么就可以得到9

接着对n进行10的整除(整除符号%)那么就可以得到1

这时只需要对两步操作分别进行平方计算即可,

六一儿童节快乐代码Python python编程题快乐数_快乐数

+

六一儿童节快乐代码Python python编程题快乐数_字符串转数值_02

 = 82。

🌈代码实现

def isHappy(n):
    while True:
        sqrsum = 0
        while n > 0:
            sqrsum += (n % 10) ** 2
            n //= 10
        if sqrsum == 1:
            return True
        elif sqrsum in [4, 16, 37, 58, 89, 145, 42, 20]:
            return False
        else:
            n = sqrsum

🌟代码注释

def isHappy(n):
    while True:  # 主循环,用来按定义判断,不用规定循环结束条件
        sqrsum = 0  # 初始化变量,用于储存计算结果和判断
        
        while n > 0:  # n最小值为零,当n=0时可省略,因为0的平方,整除,求余都为零
            sqrsum += (n % 10) ** 2
            n //= 10
            
        # 第2层while循环结束表示对n的一次(第一,第二,第,,,次判断)判断结束
        if sqrsum == 1:  # 符合快乐数定义,返回True
            return True
        elif sqrsum in [4, 16, 37, 58, 89, 145, 42, 20]:  # 不满足
            return False
        else:
            n = sqrsum  # 将前一次的判断的值赋给n,进行下一次判断

这一方法中的n=sqrsm类似于递归,可以理解成关于while循环的“递归”

✨解法二(递归直观解法)

上面规律总结法过于抽象,特别是对于(所有不快乐数的数位平方和计算,最後都会进入 4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4 的循环中。)这一结论,你只有遍历的数字得足够多才能得出这一规律。

下面我们介绍一个更加直观的解法。

我们直接按照定义遍历n,将n的每一个位数提出来进行平方和再相加。

但是我们知道数值n时不具有遍历这一属性的,不能直接去遍历n。

那我们要怎样才能遍历n?

我们可以使用str()函数把n转化位字符串,因为字符串具有遍历的属性。转换成字符串后我们就可以直接遍历n了。

但是字符串不能进行平方等操作,所以我们又需要使用int()函数将字符串转化成数值,这样就可以进行平方,求和等操作。

接着得到第一次判断的结果,那么我们只需用递归再次调用用于判断的函数再一次计算判断即可。

那么我们如何判断该数是否循环而不构成快乐数?

那么循环的特点是什么。

观察知道如果构成循环,那么必回在判断时的计算过程中出现重复的数字

那么我们可以创建一个列表记录每一次判断产生的数值,如果为1即为快乐数。不为1则将其加入列表,如果下一次判断得出的数值已在列表中出现即为循环,不构成快乐数。

🌈代码实现

def isHappy(n):
    def count(m):
        global flag
        lst.append(int(m))
        result = 0

        for i in range(len(m)):
            result += int(m[i]) ** 2

        if result == 1:
            flag = 1
        elif result in lst:
            flag = 0
        else:
            count(str(result))

    lst = []
    m = str(n)
    count(m)
    return flag == 1

🌟代码注释

def isHappy(n):
    def count(m): # m为字符串
        global flag  # 定义全局变量,确保在函数isHappy每一个处都能使用flag变量
        lst.append(int(m))  # 将m转换为数值后
        result = 0  # 初始化变量

        for i in range(len(m)):  # 遍历m
            result += int(m[i]) ** 2  # 取出每一位数进行平方后求和

        if result == 1:  # 满足快乐数的定义
            flag = 1  # 将标记值(变量)设为1
        elif result in lst:  # 判断计算出的数是否在列表内,是则不满足快乐数的定义
            flag = 0  # 将标记值(变量)设为0
        else:
            count(str(result))  # 如果还未能判断是否为快乐数,用递归再次计算判断

    lst = []  # 初始化用于储存每一次判断产生的数值
    m = str(n)  # 将n转换成字符串并赋给m
    count(m)  # 调用函数count
    return flag == 1  # 如果flag的值为1则返回True,否则返回False

为什么要设置标志值flag呢?直接用return返回True或False不更简洁吗?

事实上,如果不使用标记值flag而直接实用return(如下代码所示),那么运行函数时是不会又任何返回值的

-----------------------------------

if result == 1:

return True

elif result in lst:

return False

今天就到这,明天见。🚀

❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄end❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄