水仙花数的求解

1. 水仙花数的定义

“水仙花数”是指一个 n 位数,其各位数字的 n 次方之和确好等于该数本身,如:153= 1 ^ 3 + 5 ^ 3 + 3 ^ 3,则153是一个“水仙花数”。

2. 问题描述

求出 0 ~ 100000 之间的所有“水仙花数”并输出。

3. 求解思路

根据水仙花数的定义,要验证一个数是否是水仙花数首先要知道这个数是一个几位数,这是验证的前提,其次还要将每一位的数字提取出来,最后将这些数字分别乘以位数的次方进行验证。有了这个思路之后,就可以将验证的步骤分为以下三步:

· 待验证数是一个几位数
· 提取每一位的数字
· 每一个数字分别乘以位数的次方,然后相加,与原数相比较

只要解决了上面的三个问题,本题也就能够得到解决。

3.1 第一步

如何验证一个数是几位数?
C语言程序里面并没有相关的函数可以使用。
但是,我们不难想到可以使用求商的方法,用待验证数去除以 10 ,没除一次,就计数一次,直到待验证数变为,这样计数计了几次,那待验证数就是几位数。

如下面这段程序:

while (n!= 0)
{
	n /= 10;
	count++;
}

以 153 为例:

n 为待验证数字,count 初始值为 0.
第一次出循环:n = 15 ,count = 1
第二次出循环:n = 1, count = 2
第三次出循环:n = 0, count = 3
当 n = 0 之后,就不会再进入循环,此时, count 的数字就是 n 的位数。

3.2 第二步

如何提取一个数的每一位的数字?
再C语言中可以使用取余数的方法,将待验证的数%10,这样每次得到的结果就是每一位的具体数字了。

如下面的代码:

while (count--)
{
	m = n % 10;
	n = n / 10;
}

通过第一步我们已经知道待验证数的位数为 count ,因而我们只需要进行 count 次数的 %10就可以将每一位数字提取出来。

以 153为例:

初始值:m = 0 , n = 153 ,count = 3
第一次出循环:m = 3 , n = 15 , count = 2
第二次出循环:m = 5 , n = 1 , count = 1
第三次出循环:m = 1 , n = 0 , count = 0
当 count = 0 之后,就不会再进入循环.
此时, 待验证数就被分解为了 “1” “3” “5”

3.3 第三步

如何将提取出来的每一个数字分别乘以位数的次方,再相加?
C语言提供了一个数学函数库,里面就有一个幂函数的 pow 函数,我们只需要应用即可。
头文件:#include <math.h>
函数类型:double pow (double x, double y)
解释:x 的 y 次方

下面是结合第二步的代码:

//m 和 i 为待验证的数字
for(int j = 0; j < count; j++)
{
	sum += pow(m % 10, count);
	m /= 10;
}
	if (sum == i)
{
	printf("%d ", i);
}

当 sum 的值与待验证的数字相等的时候,这个数字就是水仙花数。

4. 代码实现

4.1 方法一:循环法

代码如下:

int main()
{
	int i = 0;
	for (i = 1; i <= 100000; i++)
	{
		int sum = 0;
		int count = 0;
		int m = i;
		int n = i;
		while (n)
		{
			n /= 10;
			count++;
		}
		for(int j = 0; j < count; j++)
		{
			sum += pow(m % 10, count);
			m /= 10;
		}
		if (sum == i)
		{
			printf("%d ", i);
		}
	}
	return 0;
}

结果如下图:
在这里插入图片描述
这个方法需要注意以下几点:

1、在进行第一步和第二步的时候,会改变待验证数的值,因而在循环刚开始的时候,要复制两个待验证数的值,也就是 n 与 m 的初始化:int m = i; int n = i;以此来避免后面无法比较。

2、每进行一次循环,都是对一个新的待验证数的判断,因而判断需要用到的临时变量每一次都要重置,最好的方法就是直接将它们的初始化放到循环体里面,如本代码里面一样。

4.2 方法二:函数法

代码如下:

int Count(int x)
{
	int count = 0;
	while (x)
	{
		x /= 10;
		count++;
	}
	return count;
}

void Judge(int x)
{
	int n = x;
	int sum = 0;
	int count = Count(n);
	for (int j = 0; j < count; j++)
	{
		sum += pow(x % 10, count);
		n /= 10;
	}
	if (sum == x)
	{
		printf("%d ", n);
	}
}

int main()
{
	int i = 0;
	for (i = 1; i <= 100000; i++)
	{
		Judge (i);
	}
	return 0;
}

此方法将步骤一变为一个函数块,将步骤二、三合并为一个函数块。
在判断一个函数是否为水仙花数的时候,只需要调用 Judge 函数即可。如果是水仙花数,则直接在频幕上显示,如果不是,则直接跳过本次的数字,直接开始判断下一个数字。

4.3 方法三:递归法

代码如下:

int Count(int x)
{
	int count = 0;
	while (x)
	{
		x /= 10;
		count++;
	}
	return count;
}

int Sum(int x, int n)
{
	if (x == 0)
	{
		return 0;
	}
	else
	{
		return pow(x % 10, n) + Sum(x / 10, n);
	}
}

void Judge2(int x)
{
	int n = Count(x);
	int m = Sum(x, n);
	if (m == x)
	{
		printf("%d ", x);
	}
}

int main()
{
	int i = 0;
	int sum = 0;
	for (i = 1; i <= 100000; i++)
	{
		Judge2(i);
	}
	return 0;
}

此方法将三个步骤分为三部分:判断位数、各个位上的数字幂次求和、判断是否为水仙花数。
其余函数与方法二几乎相同,需要强调的是“各个位上的数字幂次求和”这个函数块:

这个函数块采用递归的方法对各个位上的数字幂次求和
它的思想在于每次调用自己来求解,以 153 的求解为例:
在这里插入图片描述
求解过程图如上
· 求 153 的各个位上的数字幂次求和的时候,先将 153 的个位数字 3 提取出,3 的 3 次方加上剩下数字 “15” 的各个位数次方和就是 153 各个位上的数字幂次求和的值。
· 将“15 ”的个位数字 5 提取出来,5 的 3 次方加上 “1” 的各个位数次方和就是“ 15 ” 的结果
· 1 的提取就是本身,1 除以 10 之后为 0 ,此时进入函数迭代的结束条件,返回0
得到结果 0 之后,依次返回 1 的结果, 15 的结果和 153 的结果。

5. 总结

解决此类问题的关键在于将问题分块化,一步一步的解决当前的问题,最后再从总体的角度解决问题。

好了,今天的分享就到这里,欢迎大家留言讨论。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值