描述
自幂数是指一个 n 位数,它的每位上的数字的 n 次幂之和等于它本身,例如:13 + 53+ 3**3 = 153,编程寻找并输出 n 位的自幂数,n 由用户输入,每行输出一个数字。
n为1时,自幂数称为独身数。显然,0,1,2,3,4,5,6,7,8,9都是自幂数。
n为2时,没有自幂数。
n为3时,自幂数称为水仙花数,有4个
n为4时,自幂数称为四叶玫瑰数,共有3个
n为5时,自幂数称为五角星数,共有3个
n为6时,自幂数称为六合数, 只有1个
n为7时,自幂数称为北斗七星数, 共有4个
n为8时,自幂数称为八仙数, 共有3个
n为9时,自幂数称为九九重阳数,共有4个
n为10时,自幂数称为十全十美数,只有1个

输入格式

输入一个大于或等于 3 且小于 7 的正整数 n

输出格式

输出 n 位的自幂数,每行一个数

我们先看题目:
自幂数是指一个 n 位数,它的每位上的数字的 n 次幂之和等于它本身,编程寻找并输出 n 位的自幂数,n 由用户输入,每行输出一个数字。

1.所有的n位数是一个整数数列 ,可以由range()函数获得,,例如 n = 3时,可产生[100,1000)之间的整数数列,下面用 num 表示其中一个数。

  1. for num in range(10 ** (n-1),10 ** n):

2.整数 num 每位上的数字的获取可以用 while 循环的方法,当num 值不为0时进入循环,循环中用num对10 取模的方法获得最后一位数字。因后面需要比较获得的加和与 num 是否相等,此处先将num的值用其他名字保存一份,此处用temp,程序中用temp获取每位上的数字。

  1. while temp != 0:
  2. last = temp % 10 # 获得末位上的数字
  3. temp = temp // 10 # 获取去除末位后的数字
  1. 数字的n次幂可以用 last ** n 或pow(last,n)获得,因需要累加,所以在每测试一个新的 n位数时,要先设一个累加初值0:
  1. result = 0
  2. result = result + last ** n

4.n次幂之和可以用循环累加的方法获得,将每次循环获得的 last n 的结果加到一起;也可以将产生的 last n 置于列表 ls 中,再用sum(ls)获得列表中所有元素的和
5.如果计算的加和等于这个数本身,则输出这个数字并换行

  1. if result == num: # 判断相等要用 “==”
  2. print(num) # 无end参数时,输出后默认换行
  1. # 数学方法获得每位上的数字
  2. n = int(input()) # 输入一个整数(字符串),用int()转为整数类型
  3. for num in range(10 ** (n-1),10 ** n): # 获得所有n 位整数的数列
  4. temp = num # 将num值保存备用
  5. result = 0 # 设置累加器初值
  6. while temp != 0: # temp不为0时进入循环
  7. last = temp % 10 # 获得末位上的数字
  8. temp = temp // 10 # 获取去除末位后的数字
  9. result = result + last ** n # 将获得的最后一位上的数字的n次方累加
  10. if result == num: # 当累加和与num值相等时,num是自幂数,输出num
  11. print(num)

上面方法上用数学方法获得每位上的数字,在Python中可以将整数转为字符串,再用索引的方法获得每位上的数字:

  1. # 字符串方法的应用
  2. n = int(input()) # 输入一个整数(字符串),用int()转为整数类型
  3. for num in range(10 ** (n-1),10 ** n): # 获得所有n 位整数的数列
  4. result = 0 # 设置累加器初值
  5. for c in str(num): # 将整数num 转为字符串并通过遍历获取其中每个字符,如'370',依次获取'3','7','0'
  6. result = result + int(c) ** n # 将获得字符转为整数并计算其n次方累加,如 3 **
  7. if result == num: # 当累加和与num值相等时,num是自幂数,输出num
  8. print(num)

程序第5,6行可以合并用一个列表推导式完成。根据遍历获得的每位上的数的n次方构建一个列表,用sum()函数对列表元素进行求和。列表推导式的运用可以使程序更简洁。

  1. # 列表推导式
  2. n = int(input()) # 输入一个整数(字符串),用int()转为整数类型
  3. for num in range(10 ** (n-1),10 ** n): # 获得所有n 位整数的数列
  4. result = sum([int(c) ** n for c in str(num)])
  5. # 将整数num 转为字符串并通过遍历获取其中每个字符,用每位上的数的n次方构建一个列表。用sum()函数得到列表元素的加和
  6. if result == num: # 当累加和与num值相等时,num是自幂数,输出num
  7. print(num)
  8. # 列表推导式,合并计算与比较
  9. n = int(input()) # 输入一个整数(字符串),用int()转为整数类型
  10. for num in range(10 ** (n-1),10 ** n): # 获得所有n 位整数的数列
  11. if num == sum([int(c) ** n for c in str(num)]):
  12. print(num)

考虑到程序中需要频繁的计算数字的 n次方,当自幂数位数较多时,这个计算量还是很大的,为提升效率,可以考虑一次性的计算出 0,1,2,3,4,5,6,7,8,9的n次方备用,程序中用索引的方法获取数字的 n次方,一次计算,多次使用。计算可以用循环方式,也可以用列表推导式,此处用列表推导式实现:

  1. # 列表推导式生成0-9的n次方,程序中用索引 方式获取
  2. n = int(input()) # 输入一个整数(字符串),用int()转为整数类型
  3. ls = [x ** n for x in range(10)] # 例n 为3时 [0, 1, 8, 27, 64, 125, 216, 343, 512, 729]
  4. for num in range(10 ** (n-1),10 ** n): # 获得所有n 位整数的数列
  5. if num == sum([ls[int(c)] for c in str(num)]):
  6. # 从列表ls中索引到序号为c的元素,构建列表,如371得到列表[27,343,1],加和为371
  7. print(num)

程序中循环部分还可以用一个带条件的列表推导式实现,将print(num) 作为列表元素的,if作为推导的条件,代码可以合并到一起:

  1. n = int(input()) # 输入一个整数(字符串),用int()转为整数类型
  2. ls = [x ** n for x in range(10)] # 例n 为3时 [0, 1, 8, 27, 64, 125, 216, 343, 512, 729]
  3. [print(num) for num in range(10 ** (n-1),10 ** n) if num == sum([ls[int(c)] for c in str(num)])] # 获得所有n 位整数的数列

这种写法单行代码过长,逻辑上不容易理解,不推荐使用,但可以通过这样的方法学习推导式的各种用法,在训练时可以要求自己使用最精简的代码实现,在这个过程中,可以充分学习和利用python中的一些特性、方法和函数的各种用法,达到活学活用的目的。
更好的写法是将问题分解成两个子问题,一个是判定一个n位数是不是自幂数;一个是遍历n位整数,输出其中的自幂数。两个函数都只有一层循环和一个分支,逻辑上更清晰,建议使用。

  1. def armstrong_number(num, n):
  2. """接受一个正整数和一个位数为参数,判断是否是n位自幂数,返回布尔值"""
  3. total = 0
  4. for i in str(num):
  5. total = total + int(i) ** n
  6. if num == total:
  7. return True
  8. else:
  9. return False
  10. def judge_num(n):
  11. """接受一个大于2的正整数为参数,输出n位自幂数"""
  12. for num in range(10 ** (n - 1), 10 ** n):
  13. if armstrong_number(num, n):
  14. print(num)
  15. if __name__ == '__main__':
  16. m = int(input())
  17. judge_num(m)

因每一位上数字的n次方要被 计算多次,影响 效率,我们可以考虑先将0-9的n次方计算出来存储在列表或元组中,后面通过索引的方式获得,一次计算,多次使用,从而提高程序效率。

  1. def armstrong_number(num):
  2. """接受一个正整数为参数,判断是否是自幂数,返回布尔值"""
  3. total = 0
  4. for i in str(num):
  5. total = total + table[int(i)]
  6. if num == total:
  7. return True
  8. else:
  9. return False
  10. def judge_num(n):
  11. """接受一个大于2的正整数为参数,输出n位自幂数"""
  12. for num in range(10 ** (n - 1), 10 ** n):
  13. if armstrong_number(num):
  14. print(num)
  15. if __name__ == '__main__':
  16. m = int(input())
  17. table = [x ** m for x in range(10)]
  18. judge_num(m)

纯数学方法可以避免字符串与整数转换过程过来的性能损失,提高效率:

  1. def armstrong_number(num):
  2. """接受一个正整数为参数,判断是否是自幂数,返回布尔值"""
  3. total, tmp = 0, num # 累加初值和临时变量
  4. while tmp != 0: # 若值不为0
  5. total = total + table[tmp % 10] # tmp % 10 值为末位数字
  6. tmp = tmp // 10 # 去除末位数字
  7. return num == total # 相等时返回True,否则False
  8. def judge_num(n):
  9. """接受一个大于2的正整数为参数,输出n位自幂数"""
  10. for num in range(10 ** (n - 1), 10 ** n): # 遍历n位数
  11. if armstrong_number(num): # 判定是否自幂数
  12. print(num) # 输出
  13. if __name__ == '__main__':
  14. m = int(input()) # 输入位数n
  15. table = [x ** m for x in range(11)] # 获取x的n次幂列表
  16. judge_num(m) # 调用函数判定是否自幂数