十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

循环与拆位:5位水仙花数及素数输出编程打卡

循环与拆位:5位水仙花数及素数输出编程打卡 写代码这件事光看不行必须上手跑学计算机英语这件事光背单词不行必须放进真实的题目里读。从Day1坚持到Day18我给自己定的节奏一直很稳定每天至少两道编程题加一段计算机英语翻译今天也不例外。编程题这边正好练到循环的进阶内容——5位水仙花数以及1990到2000之间的素数输出计算机英语翻译则是Day11主题也直接围绕两道题的英文题干和常见术语展开。这篇文章适合同样在按天打卡刷题的朋友尤其是刚开始学C/C、又想顺带补一补英文文档阅读能力的同学我会把当天的题目思路、完整代码、运行结果、翻译材料以及踩过的坑一起记录下来照着跑就能跑通。1. 今日练习布局编程题与计算机英语的节奏配合1.1 为什么坚持“刷题翻译”双打卡以前我也试过“单线程”学习今天心情好刷十道编程题明天觉得英语重要又背两小时单词。结果往往是一边写代码一边查中文博客英文报错直接跳过另一边单词背到abandon就再也没翻开过。后来我把两件事强制绑在一起每天固定“编程题练习计算机英语翻译”效率明显不一样。原理很简单编程题是输出验证型学习你写没写对运行结果立刻告诉你计算机英语是输入积累型学习短期看不到回报但看英文文档和报错时离不开。把两者放在同一天恰好能形成闭环。比如今天练了5位水仙花数顺带翻译一遍它的英文题干你会在同一个晚上连续遇到Armstrong number、digit、fifth power这些词好几次记忆效果比单纯背单词表扎实得多。另一个好处是心理负担小。定一个“每天至少两道题一段翻译”的低门槛目标坚持起来不累。真遇到加班或者深夜回家我宁可少做一题也把翻译这个输入动作保留下来。英语学习最怕断档编程题断一两天还能捡起来单词和语感一旦断了重启成本很高。1.2 今日题目清单与难度排序今天的编程题有两道第一道是输出所有5位水仙花数第二道是输出1990到2000之间的所有素数要求每个素数打印一次各数之间用tab分隔。计算机英语翻译部分则是把这两道题的英文题干、关键句型和术语逐个过一遍。学习模块内容核心考点难度编程题15位水仙花数循环、拆位、幂运算、条件判断中编程题21990到2000之间的素数输出循环、试除、格式化输出中下计算机英语两道题的英文题干翻译专业名词、长句理解、术语积累中我会把编程题排序成“先素数后水仙花数”。素数判定只涉及单层循环和一个判断函数理解起来更顺水仙花数需要拆位和幂运算稍微绕一点。先做简单题建立手感再做中等题巩固循环最后翻译时把两者的术语融会贯通这个顺序不会让人一上来就卡死。2. 循环类编程题从打印到拆位的难度阶梯设计2.1 循环的编程题怎么排才不枯燥很多人对循环题的第一印象是“低级”“重复”比如单纯打印1到100写一遍就不想写了。但循环其实是编程里最重要的控制结构之一区别在于你怎么练习。我在打卡的时候给自己排了一个从易到难的阶梯每个阶段都在同一个知识点上叠加新东西第一层单层循环打印目标是把循环变量变化规律看明白比如打印1到100、打印偶数。第二层在循环体里维护一个累计状态比如求和、求阶乘、统计个数。第三层增加条件筛选比如判断素数、找完全数这需要你理解“循环遍历所有候选值用条件筛掉不满足的”。第四层拆位运算比如水仙花数、回文数、反转数字这一层把取模、整除、循环边界放在一起练。第五层嵌套循环比如九九乘法表、打印三角形图案这时候循环变量之间的关系开始变得复杂。今天两道题分别落在第三层和第四层。素数输出是典型的“筛选型循环”水仙花数是典型的“拆位型循环”。它们都不需要高级数据结构用的全是基础语法但能帮你把循环的三要素——初始化、条件、更新——彻底过一遍。很多初学者写循环时容易丢边界、忘记更新变量这两道题专门针对这些问题。2.2 5位水仙花数把“拆位”和“幂运算”练熟5位水仙花数也叫五位自幂数定义是一个五位整数它的每一位数字的五次方之和等于它本身。比如54748计算一下5的5次方是31254的5次方是10247的5次方是168074的5次方是10248的5次方是32768相加之后是54748正好等于原来的数。我为什么强调“拆位”因为这道题的核心不是幂运算而是你能不能把一个整数正确拆成单独的数字。拆位的基本工具就两个整除/去掉右边的位取模%留下右边的位。拿到万位就除以10000拿到千位就先除以1000再取个位拿到十位就先除以10再取个位个位直接对10取模。这个过程写错一个位置结果就会差很远。这个能力在后面的回文数、数字统计、进制转换里都会反复用到。所以别看它只是一道“水仙花数”把拆位练明白了很多需要逐位处理数字的题目都会变得简单。2.3 区间素数输出循环边界与控制流的综合题素数输出这道题表面上是判定素数实际上是考三件事判定的数学逻辑、区间遍历的边界、输出格式是否严格符合要求。题目要求1990到2000之间这个区间很小但设计得很巧妙里面藏着1991、1993、1997、1999这样的连续奇数足以排除那些“取巧只判断奇数”的写法。判定素数最直接的方法是试除法从2开始一直试到n的平方根如果某个数能整除nn就不是素数。为什么只试到平方根因为如果n有一个大于平方根的因数那它一定还对应一个小于平方根的因数只要小因数不存在大因数也不可能单独存在。用数学语言说判断到根号n就够了继续往后试是重复劳动。更关键的是边界条件0和1不是素数2是素数。很多人会漏掉n小于2的判断结果0和1都被误判成素数。这种错误在区间两端的题目里特别容易暴露所以我在写判定函数时第一行就处理掉特殊值。2.4 C函数题的封装思路热搜里还有一个词叫“编程c函数题”说明很多人练习的重点是把功能封装成函数。水仙花数和素数判定非常适合写成函数因为它们的逻辑独立、输入输出明确。C语言里写一个isPrime(int n)或isArmstrong(int n)返回1或0主函数里只负责调用和输出这样代码结构非常清楚。C环境下更推荐把返回值写成bool函数名用isPrimitive判断风格。如果题目要求“找出某个区间内所有满足条件的数”就再包一层函数比如void printPrimes(int start, int end)把区间遍历和结果打印也隔离出来。这样每一步都可以单独测试测isPrime(1993)是不是1测isArmstrong(54748)是不是1没问题再组合。初学阶段最容易犯的错是把所有逻辑全堆在main函数里写完自己都懒得看。养成拆函数的习惯以后调试会轻松很多这也是“函数题”训练的核心目的。3. 水仙花数完整实现从零推导到运行结果3.1 数学定义与拆位推导严格来说n位自幂数的定义是一个n位整数它的每个数字的n次方之和等于它本身。n等于3时就是我们熟悉的“水仙花数”n等于5时就叫五位自幂数也就是题目里的“5位水仙花数”。因为位数不同所以每一位要计算的是“5次方”而不是“3次方”。五位数的取值范围是10000到99999这一点容易被忽略。有人会把循环从0开始在枚举过程中过滤出“满足公式的数”但这样会把那些前导补零后满足公式的四位数也带出来比如4150和4151。把04150看作五位它也满足条件4的5次方加1的5次方加5的5次方加0的5次方加0的5次方等于4150。但4150本质是一个四位数不是题目要求的五位数。所以我在写循环边界时直接从10000起步到99999结束。这一步比任何代码优化都重要因为它决定了结果是否符合题意。严谨的做题习惯就是从读题阶段就开始确认边界。3.2 基础循环版代码与逐行解释下面是最直观的写法循环遍历所有五位数拆出每一位计算五次方和比较后输出。#include stdio.h int main(void) { for (int n 10000; n 99999; n) { int a n / 10000; // 万位 int b n / 1000 % 10; // 千位 int c n / 100 % 10; // 百位 int d n / 10 % 10; // 十位 int e n % 10; // 个位 int sum a*a*a*a*a b*b*b*b*b c*c*c*c*c d*d*d*d*d e*e*e*e*e; if (sum n) { printf(%d\n, n); } } return 0; }拆位逻辑可以这样理解n除以10000整数部分直接是万位所以a n / 10000。n除以1000后原来的万位变成十位千位变成个位再对10取模留下的就是千位所以b n / 1000 % 10。百位、十位同理个位最简单直接取模。这种写法每行只做一件事适合初学者逐句读。我刻意没有用pow(a, 5)来计算五次方因为pow返回的是double类型在浮点数转整数的过程中可能产生精度误差。虽然这道题数据量小误差概率极低但养成用整数乘法处理整数幂的习惯更稳妥尤其是在嵌入式、竞赛环境里浮点数越少越好。3.3 为什么结果是3个数而不是更多运行上面这段代码屏幕上输出的五位数只有三个54748 92727 93084初学者看到结果往往会有两个疑问一是“水仙花数不是有很多吗”二是“为什么没有别的数”。其实三位水仙花数确实只有153、370、371、407四位自幂数只有1634、8208、9474五位自幂数算出来就只有这三个。这个分布并不均匀越往上满足条件的数越稀疏。如果你把循环起点改成0会发现4150和4151也满足5次方和的公式。但就像前面说的它们是四位数的“补零版本”不是五位整数。这也解释了一个常见现象网上有些代码输出五个结果有些只输出三个区别往往就在循环边界。写题时永远以题目条件为准而不是以“公式成立”为准。3.4 函数版与pow精度陷阱用函数封装之后的代码更符合工程习惯也方便扩展到“任意位数”的场景。下面是一个通用性更好的版本用while循环逐位拆解不限定五位#include stdio.h int power5(int x) { return x * x * x * x * x; } int isArmstrong5(int n) { int temp n; int sum 0; while (temp 0) { int digit temp % 10; sum power5(digit); temp / 10; } return sum n; } int main(void) { for (int n 10000; n 99999; n) { if (isArmstrong5(n)) { printf(%d\n, n); } } return 0; }while循环拆位的好处是不管几位数都能处理。每次temp % 10得到当前最低位累加五次方然后temp / 10把最低位丢掉。这个模式在数字处理题里极其常用建议直接背下来。这里补充一个我踩过的坑在一开始的版本里我用pow(digit, 5)代码一样能跑出正确结果。但后来把五位扩展到更多位时发现浮点结果有时候是“9.999999999”这样的近似值转成int会变成9而不是10造成莫名其妙地少算。从那以后整数幂我全部改写成连乘或者自写函数。如果你在OJ上遇到“答案错误”但找不到逻辑问题可以检查一下是不是pow的精度埋了雷。4. 素数输出实操判定算法与格式化处理4.1 素数的判定逻辑为什么要试除到平方根素数也叫质数英文是prime number定义为大于1的正整数除了1和它本身之外没有其他正因数。判定一个数n是不是素数最直接的办法是从2开始试除到n-1但这样做了大量无用功。数学上有一个关键结论如果n有一个大于sqrt(n)的因数d那么n / d一定小于sqrt(n)且n / d也是n的因数。所以只要在2到sqrt(n)之间找不到能整除n的数往后也不可能有。以1993为例sqrt(1993)约等于44.6我只需要试除2、3、5、7、11、13、17、19、23、29、31、37、41、43这些不超过44的质数实际代码里从2试到44即可没有一个能整除就可以判断它是素数。在C语言里sqrt函数在math.h头文件中使用时要记得包含头文件。更保守的写法是直接写成i * i n这样既不用引入math.h也能避免浮点数比较的麻烦。两种写法都正确竞赛里常见的是i * i n。4.2 1990到2000之间的素数计算过程先列一下这个区间里所有的整数1990、1991、1992、1993、1994、1995、1996、1997、1998、1999、2000。偶数全部排除因为偶数大于2时一定不是素数。剩下来需要判断的奇数有1991、1993、1995、1997、1999。1991一眼看去像是素数但它等于11×181所以不是。1995个位是5明显能被5整除而且1995等于3×5×7×19可以直接排除。剩下1993、1997、1999三个数逐一试除后都能通过所以最终结果就是1993 1997 1999题目要求“各数之间用tab”所以中间用制表符分隔最后一个数后面可以换行不能有多余的tab。这种输出格式要求在很多在线判题系统里非常常见稍不留意就会报错。4.3 tab分隔输出的正确姿势先写一个标准的素数判定函数然后实现输出逻辑#include stdio.h #include math.h int isPrime(int n) { if (n 2) return 0; for (int i 2; i sqrt(n); i) { if (n % i 0) return 0; } return 1; } int main(void) { int first 1; for (int n 1990; n 2000; n) { if (isPrime(n)) { if (first) { printf(%d, n); first 0; } else { printf(\t%d, n); } } } printf(\n); return 0; }关键在first这个标志位。第一个素数前不打tab直接打印数字从第二个素数开始先输出一个tab再输出数字。这样就保证了所有数之间正好由一个tab分隔行首和行尾都没有多余的制表符。如果反过来写成printf(%d\t, n)每个数后面都带tab最后会多出一个孤零零的tab。很多OJ系统把这种情况判为Presentation Error不是逻辑错误但会扣分。我把这个first标志位的写法当作通用模板以后遇到“两个数之间用空格/tab分隔”的题目都按这种“先打内容再打分隔符”的顺序处理。5. 计算机英语翻译Day11用英文题干学编程术语5.1 今日翻译素材与逐句对照今天翻译的句子直接取自编程题常见的英文题干这种句子比普通对话更有价值因为它们就是以后你读LeetCode、Codeforces题目会碰到的原话。第一句是素数的定义A prime number is a positive integer greater than 1 that has no positive divisor other than 1 and itself.翻译过来是质数素数是一个大于1的正整数除了1和它本身以外没有其他正因数。这句话的语法结构并不复杂但有几个词值得注意positive integer是“正整数”greater than是“大于”divisor是“因数/除数”other than是“除了”。如果不知道divisor的含义整句就无法准确理解。第二句是五位自幂数的英文题干A five-digit Armstrong number is a number whose sum of the fifth powers of its digits equals the number itself.翻译过来是一个五位阿姆斯特朗数是指这样一个数它的各位数字的五次方之和等于这个数本身。这句话里最容易翻错的是the fifth powers of its digits。很多人看到power先想到“力量”但在这里power是“幂”的意思。digit是数字/位fifth power是五次方。整句话的核心结构是whose sum equals the number itself也就是“和等于这个数本身”。翻译时把定语从句理顺中文表达就通顺了。5.2 计算机英语高频词汇速查表今天做题过程中整理了一批必须掌握的词汇既有数学术语也有编程术语。这些词在中文资料里你不会觉得难一旦看英文题就会卡住所以建议直接按表格记。英文中文出现场景prime number素数/质数数学判定composite number合数与素数相对divisor因数/除数整除相关remainder余数取模运算digit数字/位拆位处理loop循环程序控制结构iteration迭代循环的每一轮nested loop嵌套循环多层循环break跳出结束当前循环continue继续跳过本轮进入下一轮function declaration函数声明函数题parameter参数函数传参return value返回值函数返回initialization初始化变量定义tab制表符输出格式power幂幂运算我的记忆方法很朴素不在单词表里死记而是每做一个题就把题干里出现的英文单词单独抄在一张卡片上旁边标注它在这个题目里的意思。比如今天prime number出现在“输出1990到2000之间所有的素数”被我用代码验证了一遍再想忘都难。5.3 翻译技术题干的三条经验第一条经验是“先找谓语动词再理主干”。英文技术题干通常很长里面有大量的定语从句和插入语。看到句子先圈出核心谓语动词比如is、has、equals把主谓宾找出来别的修饰成分先放一边。拿那两句翻译来说第一句的主干是“a prime number is a positive integer”后面全是修饰这个integer的第二句主干是“a number is a number”后面跟着whose引导的定语从句。主干清晰了翻译就不会乱。第二条经验是“专业名词必须在编程语境里理解”。power在普通英语里是“力量”但在数学和编程里是“幂”bit在普通英语里是“一点”但在计算机里是“比特/位”cache是“缓存”不是“躲藏”。这些词要用“编程语境词典”来查而不是随便看一个通用翻译。我在翻译练习里会专门标注这类“语境敏感词”。第三条经验是“翻译完要回读看它和代码行为是否一致”。比如翻译“输出1990到2000之间所有的素数每个素数打印一次各数之间用tab”翻译完再对照代码里的for循环和printf格式看注释和实际行为是否对得上。很多代码里莫名的注释就是从“想当然的翻译”来的。翻译题干本质上也是在训练精确表达这个能力写技术文档时特别重要。6. 打卡路上常见的坑与排查实录6.1 水仙花数输出“多出来几个数”是怎么回事这是一个很容易犯迷糊的坑。我第一次写五位水仙花数时循环偷懒写成for(int n0; n99999; n)结果输出里出现了4150和4151。当时我还很困惑验算公式也确实成立。后来才意识到4150在补上前导零后可以写成04150把它当作“五位”看每一位的五次方之和确实等于它本身但它本身不是五位数。解法有两个第一是循环从10000开始第二是在循环体内加if(n10000)过滤。核心逻辑是尊重题目中“五位数”的定义不能只满足数学公式。这个坑说明编码前搞懂题目边界比写代码更重要。遇到类似题先问自己一句话这个范围到底是“数学上成立”还是“题目要求”。6.2 素数判定边界漏判0和1被误判为素数素数判定的边界条件我至少见过三次被初学者漏掉。如果不加if(n 2) return 0这一行isPrime(0)、isPrime(1)都会返回1因为循环根本不会执行函数直接走到return 1。在区间题里如果区间恰好包含0或1输出就会多两个错误结果。排查步骤很简单写一个测试函数打印isPrime(0)、isPrime(1)、isPrime(2)、isPrime(9)几个关键值。正确的输出应当是0、0、1、0。一旦发现0和1被判定为素数就在函数开头补边界判断。这也提醒我每次写完判定类函数先测特殊值再测正常值最后测大数不要直接扔进主函数。6.3 tab分隔输出翻车行首多余前缀输出格式的翻车场景主要出在“分隔符位置”上。我第一次做这道题时图省事每个素数后面直接输出一个tab打印结果变成1993\t1997\t1999\t最后一个tab虽然肉眼看不见但评测系统能检测出来。还有一次我把tab打在数字前面结果是\t1993\t1997\t1999行首多了一个空白制表符。正确做法就是前面代码里的first标志位法。这个思路可以推广到任意“用分隔符连接元素”的场景第一个元素直接输出之后的每个元素前面补分隔符。无论是空格、逗号还是tab都遵循同一套逻辑。这个小小的输出模式在白板题和OJ题里出现频率极高值得一次记牢。6.4 计算机英语单词记了又忘怎么办计算机英语最大的问题是“背了忘忘了背”。我曾经专门背过一份互联网英文词汇表结果第二天能记住的不到一半。后来我发现单词必须放在一个“有画面感”的场景里才记得住。比如narcissistic number直译是“自恋数”。为什么叫这个名字因为希腊神话里有个美少年叫Narcissus他爱上了自己在水中的倒影最后变成水仙花。“水仙花数”这个中文译名其实就是这么来的。理解了这层背景narcissistic这个词就不会再忘。再比如prime number里的prime本义是“首要的、最重要的”所以prime number就是那些“本质上不可再分解的数”和The prime objective首要目标里的prime是同一个词根。这样顺藤摸瓜一个词能串起一串词。打卡到今天的最大体会就是编程题练的是一种“把问题翻译成代码”的能力计算机英语练的是一种“把英文翻译成逻辑”的能力两者都离不开重复和语境。我现在遇到生僻术语不会单独背而是先做题再去看这道题的英文题干把单词放进真实场景里记印象比单词表深得多。如果你也在刷题建议从今天开始把题目旁边对应的英文术语抄一遍再做一次计算机英语翻译练习坚持几周之后你再看英文报错和官方文档会轻松非常多。
返回列表