【C语言】水仙花数

问题

水仙花数(Narcissistic number)也被称为超完全数字不变数(pluperfect digital invariant, PPDI)、自恋数、自幂数或阿姆斯壮数数(Armstrong number)。

它是指一个n位数(n≥3),它的每个位上的数字的n次幂之和等于它本身。例如:1^3 + 5^3 + 3^3 = 153,则153是一个水仙花数。对于三位数,水仙花数有153、370、371、407四个数。

这里我们扩大一点范围,假设水仙花数也可以小于三位数,只要一个n位数各位数字的n次方之和确好等于该数本身,我们就认为它是水仙花数,那么现在我们求出0~100000之间的所有“水仙花数”并输出。

整体分析

我们可以拆分一下我们到底要做哪几件事,就像你现在要煮一碗拉面,你可以将整个过程拆分为去买菜、备菜、煮面、吃、洗碗。解决这个问题,我们可以拆成生成0~100000的数组,求每个数是几位数(此时假设位数为n),求每个位上的数字的n次方之和(还可以进一步细分为求每位的n次方、求和两个动作),判断是否是水仙花数、打印这几件事。

具体分析

首先,生成0~100000的数字,这是最简单的,只需要一个循环语句:

int main()
{
   int i = 0;
	   for(i=0; i<100000; i++)
	   {
           //具体的:计算位数n、求各位n次方和、判断是否为水仙花数和打印
       }
   return 0;
}

现在,我们就有了最外层的框架。

求几位数

怎么样才能得到这个数是几位数呢?这里我们可以用一种办法,我们知道,‘/’是整除,所以一个数/10的结果是去掉了最低位:

int a = 123;
int a = a/10;//将a整除10的结果重新赋值给a,现在a的值变为了12

那么,我们可以循环这个过程,定义一个变量count初始化为0,让我们的i每次/10后都count++,当i等于0的时候整除停止,此时我们得到的count就是位数:

看完这个图你一定就理解了吧。

得到各位上数字的count次方和

怎么做到这一点呢?我们知道一个数%10得到的就是最低位上的那个数字…等下,你不知道为什么?那我先浅浅讲解一下,已经知道的朋友可以跳过这段:

C语言中的%符号有两种主要用法:作为格式化字符串中的占位符和作为取模运算符,我们这里用到的是后一种。

%用作取模运算符时,表示整数除法的余数。例如,result = a % b; 计算的是 a 除以 b 的余数,并将结果赋值给 result。

使用%d时,确保对应的变量是整数类型(int),如果是长整型(long)则使用%ld或%Ld,短整型(short)使用%hd。

在进行取模运算时,要注意除数不能为零,否则会导致程序运行错误。

那么为什么一个数%10得到的就是最低位上的那个数字呢?我们这里说的“一个数”指的是十进制表示的一个数。%计算的是除之后的余数,%10就是除10后的余数,因为是十进制,所以剩在最低位上的就是无法达到10从而进位的数,所以也就是%10的余数。

这么说,应该能够理解了吧。

但是一次%10我们只能得到一个数字最低位的数啊,怎样才能把每一位的数字都拿到呢?其实我们的“武器”还是循环。而且我们还要借助上面刚提过的/10,因为将一个数/10就是整除10,而效果就是去掉了最低位,所以我们拿到一位、去掉一位、再拿一位、再去一位,不就能从低到高拿到每一位了吗?

既然我们要拿到每一位,并且要求它们的count次方的和,这时我们就创建一个变量sum,用来每轮循环存放这一位n次方的值,随着循环进行累加。

在C语言中我们想要求一个数的几次方,我们需要用到一个函数叫做pow,它的头文件为math.h,它所需的两个参数前者就是要求次方的数,后者就是几次方。

在了解这些后我们就能写出这个循环:

while (i)
{
	sum += pow(i % 10, count);
	i = i / 10;
}
陷阱

但是我的朋友,你先别高兴得太早,以上的代码其实有一个很难察觉的陷阱,这也是我在调试之后才找出来的:

对于后面这个求次方和的代码来说,此时的i在经过前一个循环后已经变成0而不是它原本的数字了。 那么我们根本都无法进入后面这个循环。其实,到最后判断的时候我们还要用到一次i的原始值。

那么怎么解决这个问题呢?

其实解决办法很简单,我们的目标就是不去改动i的值,那么我们只要在一开始就把i的值先赋给一个变量,并且在它需要变回i的值的时候,把i再赋一次给它就行了。所以以上两个循环应该改为:

for (i = 0; i < 100000; i++)
{
    
    int sum = 0;//这个要写在里面,否则对于每一个要检测的i来说,sum就不是从零开始了
	int count = 0;//这个也要写里面,理由同上。

	int tmp = i;//tmp接受i真正的值,替i进行变化,不用改动i

	while (tmp)
	{
		count++;
		tmp = tmp / 10;
	}

    tmp = i;//让tmp重新变回i的值

	while (tmp)
	{
		sum += pow(tmp % 10, count);
		tmp = tmp / 10;
	}
}
最终判断

现在,几位数(count)有了,各位上数字的count次方和有了,我们只需要拿和与我们的i进行比较判断就行了:

if (sum == i)
	printf("%d ", i);

完整代码参考:

在vs2022上运行效果:

那么,本篇博客内容到此就结束了,希望大家看完发现问题向我反馈,共同进步! 

  • 47
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值