Python 判断一个数是否为水仙花数(手把手讲解)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

什么是水仙花数?

水仙花数(Narcissistic Number),也被称为超完全数字不变数或自恋数,是指一个 n位数 满足其各位数字的 n次幂之和 等于该数本身。例如,三位数的水仙花数需要满足:
abc = a³ + b³ + c³

这个概念来源于数学中的数论,因其独特的对称性和自相似性,常被用作编程入门的实践题目。通过理解水仙花数的判断逻辑,开发者可以掌握数字拆分、幂运算等基础编程技巧,同时培养逻辑分析能力。


水仙花数的数学原理解析

1. 数学定义的分解

水仙花数的核心在于 位数与幂次的关联性。例如:

  • 三位数水仙花数:位数n=3,因此每个数字需要计算三次方
  • 四位数水仙花数:位数n=4,每个数字计算四次方

这类似于数学中的“自我指涉”概念,即数字的结构决定了其自身的计算规则。

2. 数字拆分的两种方法

判断水仙花数需要先将数字拆分为各个位上的数字。常用方法有两种:

  • 字符串转换法:将数字转为字符串,逐个字符提取
  • 数学运算法:通过取模(%)和整除(//)操作逐位分离

类比比喻
想象一个三位数像三明治的三层结构,字符串方法是“切片”分开,而数学方法则是“分层剥离”。


Python实现的步骤解析

第一步:确定数字的位数

对于任意整数,可以通过以下方式获取位数:

def get_digits_count(number):
    count = 0
    n = abs(number)  # 处理负数的情况
    while n > 0:
        n = n // 10
        count += 1
    return count

代码解释

  • 通过循环不断去除最后一位数字(n = n // 10),直到数字变为0,循环次数即为位数。

第二步:提取每一位数字

方法1:字符串转换法

def get_digits_str(number):
    return [int(digit) for digit in str(number)]

方法2:数学运算法

def get_digits_math(number):
    digits = []
    n = abs(number)
    digits_count = get_digits_count(n)
    for _ in range(digits_count):
        digit = n % 10
        digits.append(digit)
        n = n // 10
    return digits[::-1]  # 反转以恢复原始顺序

对比分析

  • 字符串方法简洁但可能牺牲效率(需类型转换)
  • 数学方法运算量稍大,但适合处理非常大的数字

第三步:计算各位数的幂次和

def narcissistic_sum(digits, power):
    return sum(digit ** power for digit in digits)

关键点

  • 幂次(power)必须等于数字的位数
  • 使用列表推导式高效遍历所有数字

第四步:整合判断逻辑

将上述步骤组合成最终函数:

def is_narcissistic(number):
    if number < 0:
        return False  # 负数不考虑
    digits = get_digits_math(number)
    power = len(digits)
    return sum(digit ** power for digit in digits) == number

完整代码示例与测试

示例1:判断三位数的水仙花数

print(is_narcissistic(153))  # 输出:True(1^3 + 5^3 + 3^3 = 153)
print(is_narcissistic(370))  # 输出:True
print(is_narcissistic(371))  # 输出:True
print(is_narcissistic(407))  # 输出:True
print(is_narcissistic(123))  # 输出:False

示例2:四位数的水仙花数

print(is_narcissistic(1634))  # 输出:True(1^4 + 6^4 + 3^4 +4^4 = 1634)
print(is_narcissistic(8208))  # 输出:True
print(is_narcissistic(9474))  # 输出:True

进阶优化:提升代码效率

优化点1:减少重复计算

在原始代码中,get_digits_mathget_digits_count 会重复计算位数。可通过合并逻辑优化:

def get_digits_and_power(number):
    digits = []
    n = abs(number)
    power = 0
    while n > 0:
        digit = n % 10
        digits.append(digit)
        n = n // 10
        power += 1
    return digits[::-1], power

优化点2:提前终止循环

在计算各位数幂次和时,若中间结果超过原数,可提前终止循环:

def narcissistic_sum_optimized(digits, power):
    total = 0
    for digit in digits:
        total += digit ** power
        if total > number:  # 提前判断是否超出
            return total
    return total

实际应用场景与扩展

场景1:生成指定范围内的水仙花数

def find_narcissistic_numbers(start, end):
    results = []
    for num in range(start, end + 1):
        if is_narcissistic(num):
            results.append(num)
    return results

print(find_narcissistic_numbers(100, 999))  # 输出三位数的所有水仙花数

场景2:探索高次幂水仙花数

例如五次幂的水仙花数:

print(is_narcissistic(54748))  # 输出:True(5^5 +4^5+7^5+4^5+8^5 = 54748)

常见问题与解答

问题1:为什么0不被视为水仙花数?

根据定义,水仙花数需满足各位数字的n次幂之和等于自身。0的位数可视为1,但 0^1 = 0,理论上符合条件。但通常约定不包含0,需在代码中明确处理。

问题2:如何处理负数?

负数的各位数字幂次和无法为负数,因此直接返回False。

问题3:是否存在多位数的水仙花数?

是的,例如四位数、五位数等都有对应的水仙花数,但计算量会随位数增加而指数级增长。


总结与学习建议

通过本文,我们系统学习了如何用Python判断水仙花数。这一过程不仅巩固了数字拆分、循环和条件判断的基础知识,还涉及了算法优化的实践技巧。对于初学者,建议:

  1. 先手动计算几个例子,理解数学逻辑
  2. 逐步调试代码,观察每一步的中间结果
  3. 尝试扩展代码,探索更多位数的水仙花数

掌握这一技能后,可以进一步挑战其他数论问题,如完全平方数、回文数等,逐步构建自己的算法工具箱。

最新发布