(“拨”取数字的典例:N位水仙花数判断及水仙花数变种)

简介: 这篇内容介绍了如何判断和生成水仙花数,水仙花数是一个n位数,其各位数字的n次方之和等于该数本身。文章首先回顾了"拨数"的概念,然后通过实例展示了如何判断三位水仙花数,并将其推广到任意位数的水仙花数。作者提供了详细的解题思路和代码示例,强调了解决这类问题时要慢下来,分步骤分析问题。最后,文章还探讨了一个水仙花数的变种问题,即数字拆分后乘积之和等于原数的情况。


前言:再论“拨”取数位上的数


在我曾经的博客中提到过,“水仙花数”类型的题目,精髓就在于“拨数”。关于“拨数”的内容,在往期的文章中已经详细讨论过,本文便不再赘述。我们将“拨数”作为一个大家已经掌握了的知识储备,再来讨论水仙花数系列的习题。


C语言编程必会技能:“拨”取数位上的数

http://t.csdn.cn/W0iPx


三位水仙花数,即其个位、十位、百位数字的立方和等于该数本身。这是我们常见的水仙花数题,它的讨论范围限定在3位数。事实上,水仙花数可以不止有3位数,但它们的运算规则是相同的:


一个n位数,其各位数字的n次方之和恰好等于该数本身。于是就有:


三位的水仙花数共有4个:153,370,371,407;

四位的四叶玫瑰数共有3个:1634,8208,9474;

五位的五角星数共有3个:54748,92727,93084;

六位的六合数只有1个:548834;

七位的北斗七星数共有4个:1741725,4210818,9800817,9926315;

八位的八仙花数共有3个:24678050,24678051,88593477


我们干脆将所有具有该特点的数成为水仙花数。


本文讨论的重点在于,如何判断一个任意数位的水仙花数。我们再次巩固和运用“拨数”大法来解决问题,文末附上了水仙花数的变种:


把任意的数字,从中间拆分成两个数字,如果所有拆分后的乘积之和等于该数本身。


希望本文能让诸位读者对数位拨取类习题有更深刻的理解。


一、引例:三位水仙花数


1. 题干


输出所有水仙花数。


水仙花数是一个3位数,各位数字的立方之和等于他本身,例如:153= 13+53+33。


2. 思路


实现3位水仙花数是一件很容易构思的事情。先把三位数中个位、十位、百位上的数字取下来,然后进行立方求和运算,最后判断是否与原数相等即可。


3位水仙花数数位确定,且幂仅是三次方(幂数较少),实现起来并不复杂。大致分为两步:


1. 取数字


2. 计算并判断是否相等。


3. 代码


#include<iostream>
 
int main(){ 
  int flowerN,ge,shi,bai;
 
  for(flowerN = 100; flowerN < 1000; flowerN++){
        //拨取数位上的数
    ge = flowerN%10;
    shi = flowerN/10%10;
    bai = flowerN/100%10;
 
    if(flowerN == ge*ge*ge + shi*shi*shi + bai*bai*bai){
      printf("%d ",flowerN);
    }
  }
 
    return 0;
}


二、推广:N位水仙花数


1. 题干


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


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


2. 思路


有些同学在这道题卡住,很大的一个原因是,当具象的“3”变成抽象的“n”时,比较难以想象该如何让代码做到普适。当感觉一团乱麻的时候,我们依旧可以考虑用上次讲到的分析问题“三板斧”(举例、模拟(必要时画图)、找规律)进行考虑。


碳基肥宅:分析破题“三板斧”

http://t.csdn.cn/ykGeV


有了计算3位水仙花数的经验(3位水仙花数正是一个特例,很好地帮助我们完成了“举例”这第一板“斧”),我们可以直接将问题切割为三个大步骤,再逐步求精:


1. 一共有多少个数位?这决定了一共有多少个数要拨取并相加,以及相应的幂数。


--求位数


2.求数的n次方。


3.累加:求每个数位上的数的n次方之和。这需要对叠加的算法熟悉。


以上,我们将一个大问题分割成了几个小的功能模块。在编程时,我们只需要照着这些小的功能模块逐步完善求精即可。


详细说明上述思路不是没有意义的。我们需要有意识地在编程分析问题时“慢下来”,分割大问题,完善小问题,才能保证编程的顺利。相比起拿到题目就从头开始干,想到哪里写到哪里,一运行bug肆虐,我认为这样有规划地写代码,确实是更好的选择。


3. 代码


#include<stdio.h>
#include<math.h>
 
//求出整数的位数n -- 拨取数位上的数
int digits(int num){
  int n = 1;
  while(num/10){
    n++;
    num /= 10;    //这一句注意不要遗漏!!否则就是死循环
  }
  return n;
}
 
//判断是不是水仙花数,是返回1,不是返回0
int isNumber(int num){
  int n = digits(num);    //调用函数,获取数位
  int sum = 0;
  int tmp = num;    //把num的值先保存起来,便于后续比较
 
  while(num){   
    sum += pow(num%10,n);    //可以类比叠加的算法
    num /= 10;
  }
  
  if(sum == tmp){
    return 1;
  }else{
    return 0;
  }
}
 
int main(){
  
  for(int num = 0; num <= 100000; num++){
    if(isNumber(num)){
        printf("%d\n",num);
    }
  }
  return 0;
}


说明

1. while循环中,千万不要忘记num /= 10这一步骤。这是循环变量的调整步骤,没有这一步程序会死循环。由于while(num / 10)和num /= 10这一步有些相像,num /= 10这一步就很容易漏写。


2. int tmp = num;这一步很关键。它是将num的值暂时保存到tmp中,最后比较时,也是将sum与tmp比。因为num同时作为循环变量,它是不断变化调整的。当while执行结束后,num早已不是我们最初输入的那个值。最后sum要和“该数本身比较”,num早已不是“该数本身”。因此我们需要再创建一个变量,拷贝出num最初的值备用。


这一步非常隐蔽,很容易直接按照预先想好的逻辑上手而将它忽略。这样程序当然会出bug。我第一次编写代码时,正是遇到了这个问题,看了很久调试后才发现问题所在。一不小心,就花费了很多的时间。


三、拓展:水仙花数的变种 -- 灵活“拨”取数字


1. 题干



牛客网习题链接


BC38 变种水仙花

https://www.nowcoder.com/practice/c178e3f5cc4641dfbc8b020ae79e2b71?tpId=107&&tqId=33319&rp=1&ru=/ta/beginner-programmers&qru=/ta/beginner-programmers/question-ranking


2. 思路


三板斧的使用


举例


这道题相比上面的题目,难度未必有所提升。我们直接以五位数12345为例,对这个情况进行模拟。


模拟


num:12345。以下示意程序运行时达到的效果:


  • 1234  5

     12345/10 * 12345%10

  • 123  45    

     12345/100 * 12345%100

  • 12  345

     12345/1000 * 12345%1000

  • 1  2345

     12345/10000 * 12345%10000


找规律


我们发现,同一组内,除数与模数始终相等,且从10开始变化到10000.我们将该数设定为循环变量i,i从10变化到10000,且每次增长10倍。


而被分隔成的左右两个数,一个是num%i的结果,一个是num/i的结果。


因此,将规律整合成为如下代码即可:


3. 代码


#include<stdio.h>
 
/*
12345
1234 5
12345/10 * 12345%10
123 45    
12345/100 * 12345%100
12 345
12345/1000 * 12345%1000
1 2345
12345/10000 * 12345%10000
*/
 
 
int isLily(int num){
  int tmp = num;
  int sum = 0;
  for(int i = 10; i <= 10000; i*=10){
    sum += (num/i)*(num%i);
  }
  if(sum == tmp){
    return 1;
  }
  return 0;
}
 
int main(){
    
    for(int i = 10000; i < 100000; i++){
        if(isLily(i)){
            printf("%d ",i);
        }
    }
    
    
    return 0;
}


四、总结


1. 编写代码时可以考虑先分隔功能模块,再逐步求精。


2. 水仙花数从3位到n位的推广:找相似。

相关文章
|
7月前
【刷题日志】深度理解除(/)与取模(%)附水仙花数以及变种水仙花数题解
【刷题日志】深度理解除(/)与取模(%)附水仙花数以及变种水仙花数题解
|
7月前
|
算法 编译器 C语言
题目----水仙花数问题的实现以及对于数字每位数的求解原理分析
题目----水仙花数问题的实现以及对于数字每位数的求解原理分析
64 0
|
7月前
|
C语言
每天一道C语言编程(2):自守数
每天一道C语言编程(2):自守数
132 0
|
C语言
【C语言初学必看】水仙花数、变种水仙花数背后的知识
【C语言初学必看】水仙花数、变种水仙花数背后的知识
160 0
变种水仙花数
变种水仙花数
66 0
遇7避过(输出1~100内的安全数,安全数不能带有7,不能被7整除
遇7避过(输出1~100内的安全数,安全数不能带有7,不能被7整除
75 0
判断数的奇偶性
判断数的奇偶性
100 0
每日一题——“水仙花数”
哈喽大家好,我是保护小周ღ,本期为大家带来的是求“水仙花数”,此水仙花,非彼水仙花,一起来看看把~
127 0
打印0~100000之间的水仙花数, 水仙花数指一个n位数,其各位数的n次方之和正好等于该数本身
打印0~100000之间的水仙花数, 水仙花数指一个n位数,其各位数的n次方之和正好等于该数本身
119 0