文章目录
- 💯前言
- 💯题目描述
- 💯我的做法
- 思路分析
- 优势
- 不足之处
- 💯老师的做法
- 思路分析
- 优势
- 不足
- 💯对比和优化
- 实现方式对比
- 优化思路和操作
- 1. 直接分解数字的各位
- 2. 展开至任意位数水仙花数
- 💯小结
💯前言
- 在程序设计中,“水仙花数”是一个带有数学特色的热点题目。这个题目最核心的思路在于如何分解三位数,并检查它是否满足水仙花数的定义。通过进一步分析、优化,我们不仅能学习到原理,还可以探索于实现与效率之间的平衡点。本文将从题目解读、我的实现、老师做法、思路对比与优化,以及指向临水仙花数更学机。
C++ 参考手册
💯题目描述
2029:【例4.15】水仙花数
题目要求如下:
- 计算 100 到 999 中的水仙花数
如果三位数 ( ABC ) 满足以下条件:
A B C = A 3 + B 3 + C 3 ABC = A^3 + B^3 + C^3 ABC=A3+B3+C3
则称 ( ABC ) 为水仙花数。
例如:三位数 153 ,其三位系数分别是:
1
3
+
5
3
+
3
3
=
1
+
125
+
27
=
153
1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153
13+53+33=1+125+27=153
则 153 是水仙花数。
输入:
- 无需输入
输出:
- 由小到大输出满足条件的数,每个数单独一行。
示例输出:
153
370
371
407
💯我的做法
我的做法如下:
#include <iostream>
using namespace std;
int main()
{
for (int i = 100; i <= 999; i++) // 遍历所有三位数
{
int m = i; // 存储当前数字
int count = 0; // 积累各位系数的立方和
while (m)
{
int j = m % 10; // 取位:下一个位系数
count += j * j * j; // 计算立方并积累
m /= 10; // 清除最低位
}
if (count == i) // 检查积累立方和是否等于原数字
cout << i << endl; // 输出
}
return 0;
}
思路分析
- 通过
for
循环遍历 [100, 999] 范围内的所有数字,以判断每个数字是否是水仙花数。 - 通过循环中的初始化:
- 用临时变量
m
存储当前数字,无需直接操作原数。 - 定义
count
用于积累各位系数立方和。
- 用临时变量
- 通过内部
while
循环:- 取位系数:通过
m % 10
获得最低位; - 计算立方值并积累:通过
j * j * j
直接计算立方值; - 清除最低位:通过
m /= 10
,将数字左移一位;循环至数字为 0 为止。
- 取位系数:通过
- 检查立方积累和是否等于原数,如等,则输出。
优势
- 简洁直观: 计算每个位系数立方直接通过三次乘法完成,避免使用更复杂的函数。
- 处理简单: 通过循环直接完成数字分解、积累立方和,无需额外函数调用,更实用。
不足之处
- 总处理时间复杂度为 ( O(n \times d) ),对于三位数,( d ) 是 3,因此复杂度为实际上是存在优化空间的,如果可直接计算各位,则可省去一些循环操作。
- 输出格式比较基本,如需更好看的输出,可选择增加分隔符。
💯老师的做法
老师的代码如下:
#include <iostream>
#include <cmath> // 引入函数 pow
using namespace std;
int main()
{
for (int i = 100; i <= 999; i++) // 遍历所有三位数
{
int tmp = i; // 临时处理数字
int ret = 0; // 积累各位系数立方和
while (tmp)
{
ret += pow(tmp % 10, 3); // 取位和立方,使用pow函数
tmp /= 10; // 清除最低位
}
if (ret == i) // 检查积累立方和是否等于原数
cout << i << endl; // 输出
}
return 0;
}
思路分析
-
核心比较:使用
pow
函数计算立方:
老师的做法并没有用直接乘法计算立方,而是使用了标准库中的pow
函数。这样做的好处是:在基础程序教学中,比较直观,学生能学习标准函数的应用;同时使用pow
计算任意次方,优质显而易见。 -
居有化简:进一步生成临时变量,直接取位计算,治理系统优化:
基于基础计算源,老师用tmp
分解,保留原数,从维护和计算的规范性方面,有较高的规范性和应用性。
优势
- 可读性更好: 使用
pow
函数,明确表达了“次方”的概念,更便于基础教学和理解。 - 通用性更强: 如需更改次方,可直接修改为
pow(tmp % 10, n)
,适配与任意次方计算,更具通用性。
不足
- 性能突出较少: 使用
pow
函数导致调用源库,效率上不如直接乘法。在计算量不大时,注意不显著;但如若展开到更大的数据量,远不如乘法计算的效率高。
💯对比和优化
实现方式对比
方式 | 核心思想 | 优势 | 不足 |
---|---|---|---|
我的做法 | 通过三次乘法直接计算立方 | 性能高,逻辑简洁,极对化 | 相对基础学生,学习成本较高 |
老师做法 | 使用 pow 函数计算立方 | 可读性好,通用性强 | 性能不如直接乘法,有调用源库的增加费用 |
优化思路和操作
在经典做法上,如下作举可能更加高效和实用:
1. 直接分解数字的各位
使用数学运算分解数字的各位,无需循环:
#include <iostream>
using namespace std;
int main()
{
for (int i = 100; i <= 999; i++)
{
int a = i / 100; // 百位
int b = (i / 10) % 10; // 十位
int c = i % 10; // 个位
if (i == a * a * a + b * b * b + c * c * c)
cout << i << endl;
}
return 0;
}
这种做法可以直接获取各位,避免伴随调用和循环,效率更高。
2. 展开至任意位数水仙花数
通过使用函数展开计算任意位数的水仙花数:
#include <iostream>
#include <cmath>
using namespace std;
// 检查水仙花数
bool isArmstrong(int n)
{
int sum = 0, tmp = n;
int digits = log10(n) + 1; // 位数
while (tmp)
{
sum += pow(tmp % 10, digits); // 次方积累
tmp /= 10;
}
return sum == n;
}
int main()
{
for (int i = 100; i <= 999; i++)
{
if (isArmstrong(i))
cout << i << endl;
}
return 0;
}
💯小结
通过对我和老师做法的分析,我们能看到:
- 核心思想相同: 我和老师都是通过数字分解和立方积累,实现水仙花数的检查。
- 实现途径带有小差异: 我的做法更重视性能,老师做法更重视可读性。
- 优化思考: 通过直接分解数字和展开至任意位数,可以更加高效和通用。
在实际经验中,可根据场景和需求选择最适合的方案,例如教学中选择通过性更强的方案,而在效率优先的场景下,可选择性能更高的直接乘法。求真时,始终是计算积累的深层探索!