尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

经典编程练习简单卷:夯实编程基础与边界思维的必刷清单

经典编程练习简单卷:夯实编程基础与边界思维的必刷清单 如果让我给刚学编程的人推荐第一份练习清单我大概率会甩出一份“经典编程练习-简单卷”。名字听着有点朴素但它解决的问题非常实在语法书翻了三遍还是写不出完整程序看视频课程时觉得全会、自己上手时大脑一片空白。这套简单卷用二三十个短小精悍的题目把变量、循环、判断、数组、函数这些最基础的能力挨个练到位非常适合零基础起步的新手也适合已经工作一两年、想回来补基本功的开发者用来查缺补漏。我在带新人的时候反复说过一句话编程能力的差距很多时候不是差在新技术上而是差在这些“简单练习”背后的基本功上。你让一个新手去聊异步编程、AI编程、并发编程他能给你说出一堆名词但你让他写一个闰年判断、一个九九乘法表代码可能惨不忍睹。这套简单卷的价值恰恰是把这些“你以为你会了”的东西真正练成肌肉记忆。这篇文章我会把这套练习的核心题目逐一拆开来讲包括每道题的思路、代码、常见坑位以及我从这些简单练习里总结出来的工程经验。内容尽量说人话保证能看懂、能复现。1. 简单卷不等于水题这些经典练习到底在练什么1.1 为什么我建议编程新手认真刷完这一套很多人一上来就啃高深的技术我见过不少新手第一个项目就是模仿开源商城系统结果连if和for的嵌套关系都没理清楚代码报错后连日志都不会看硬生生把热情磨没了。经典编程练习-简单卷的好处就是题目足够小每道题都只需要花十几分钟到半小时能够快速得到成就感。这个“小”字很关键。心理学上有个概念叫“心流状态”简单卷的题目难度刚好能让你处在“有点挑战但够得着”的状态。如果题目太难你会陷入挫败太简单又会觉得无聊。经典练习的难度曲线设计得比较合理从输入输出、条件判断到循环嵌套、函数封装每一关都在前一步的基础上增加一点点复杂度练完以后你会明显感觉到自己写代码的速度和准确率都在提升。更重要的是简单卷在训练一种“从题目到代码”的翻译能力。很多新手的真实困境不是不会语法而是不会把自然语言描述转换成逻辑步骤。比如题目说“判断一个年份是否为闰年”新手脑子里会冒出一堆问题怎么输入怎么输出闰年规则是什么边界条件怎么处理这套练习的核心价值就是在反复训练你完成这种“需求翻译”这是所有编程工作最底层的素养。1.2 简单卷的题目设计逻辑与能力覆盖我翻过很多套经典练习发现无论题目集怎么变覆盖的能力点都高度一致。你可以把整个简单卷理解成一个“编程基础能力体检表”每道题对应一个能力点能力维度典型题目训练目标输入输出读入两个整数并求和input/scanf的标准用法类型转换条件分支判断闰年、求绝对值多重条件的优先级边界思维循环控制九九乘法表、水仙花数循环嵌套、循环变量控制数据组织数组逆序、求最值索引、遍历、状态记录函数封装计算阶乘、判断素数参数传递、返回值、模块化思维字符串处理回文判断、字符统计不可变性、索引和切片操作简单算法冒泡排序、去重嵌套循环、交换逻辑、标记思想不要小看这份“体检表”。我面试过不少候选人简历上写着精通 Java、熟悉微服务结果让他手写一个字符串反转考虑了半分钟还写不出来。这种人往往就是当年跳过了“简单卷”直接追热点导致的。基本功不扎实上层建筑都悬空。另外还有个容易被忽略的点这套练习能帮你养成“代码风格”。同一道题新手可能写出一坨只有自己能看懂的代码而有经验的程序员写出来的结构是清晰、有注释、变量名有意义的。在练简单卷的时候你就应该有意识地培养这个习惯而不是等到接手真实工程才被迫改。2. 五个核心经典题拆解思路、代码与边界2.1 简单卷里的“钉子户”闰年判断的条件分支闰年判断是经典中的经典也是很多教材讲条件分支时的首选例子。这个题目看似只考一个公式实际上藏着很多编程中最重要的思维边界处理。闰年的规则是能被4整除但不能被100整除或者能被400整除。很多新手一上来就写year int(input()) if year % 4 0: print(是闰年) else: print(不是闰年)这个代码在大多数测试用例下看不出问题但一旦输入1900就翻车了——它会被错误地判断为闰年。正确的写法有很多种我比较推荐这一版def is_leap(year): return (year % 4 0 and year % 100 ! 0) or (year % 400 0)我第一次带人写这道题时就强调过代码不是“能跑”就行而是要在所有情况下都对。判断闰年这类条件题核心是训练你“找全情况”的能力。你要主动去列边界值0年负数极大年份在真实业务里你以为只处理正常情况就够了结果线上被极端数据击穿这就是边界意识缺失的代价。如果换成 C 写bool isLeap(int year) { return (year % 4 0 year % 100 ! 0) || (year % 400 0); }注意这里的运算符优先级的优先级高于||所以表达式的计算顺序是符合预期的。新手最容易在这类“一行逻辑”上栽跟头我建议你写的时候可以加一对括号明确分组既避免优先级错误也让读代码的人一眼看懂意图。2.2 九九乘法表双重循环与输出格式控制九九乘法表是我心目中“简单卷的守门员”。如果你能独立写出整齐的九九乘法表说明你对循环、嵌套、输出格式控制都有了基本概念如果写不出来那后面的练习题大概率会遇到困难。先看正解for i in range(1, 10): for j in range(1, i 1): print(f{j}x{i}{i*j:2d}, end ) print()关键点在range(1, i 1)这个内层循环范围。很多新手会写成range(1, 10)结果输出了一个完整的矩形而不是三角形。这里的“为什么是i 1”就是典型的循环边界思维。要是用 C 写更明显for (int i 1; i 9; i) { for (int j 1; j i; j) { printf(%dx%d%2d , j, i, i * j); } printf(\n); }另一个坑是输出格式。Python 里默认的print会在末尾追加换行符所以你需要用end 来覆盖它让同一行的算式之间保持空格。C 的cout没有自动换行新手经常忘了加endl或者\n导致所有输出挤在一起。我面试时特别喜欢让候选人现场写这道题因为它能在一分钟内暴露你的基本功循环变量用错、边界少一、忘记换行、格式不对齐这些问题会全部现形。如果你能流畅地写出来并且还能顺带说一句“内层循环条件为什么是j i”那说明你确实理解了嵌套循环的本质。2.3 斐波那契数列递归与迭代的权衡斐波那契数列是经典中的经典几乎每套练习里都有它。题目本身很简单数列第1项是1第2项是1从第3项开始每一项是前两项之和输出前N项。新手最容易写出的版本是递归def fib(n): if n 2: return 1 return fib(n - 1) fib(n - 2)这个版本简洁易读但性能非常糟糕。我实测过计算第40项时递归版已经明显卡顿第50项基本等不到结果。问题在于fib(n - 1)和fib(n - 2)之间产生了大量重复计算同一个子问题被反复求解时间复杂度达到了指数级。迭代版本就好得多def fib(n): a, b 1, 1 for _ in range(n - 1): a b b a b # 这里要注意Python 的 a, b 赋值是同时进行的 return a在 Python 里更稳妥的写法是a, b b, a b这样能避免中间变量的覆盖问题。C 的写法也一样long long fib(int n) { long long a 1, b 1; for (int i 1; i n; i) { long long temp b; b a b; a temp; } return a; }这道题真正想训练的不是“背出递归公式”而是让你意识到解决问题可以有多种思路但你要学会评估不同方案的性能差异。这个评估意识会伴随你整个编程生涯——无论是写异步编程还是做系统设计你天天都在做这种取舍。2.4 素数判断从“能跑”到“高效”的第一次优化素数判断是练习“优化思维”的绝佳载体。最朴素的写法是从2遍历到n-1一个个判断能否整除。这个写法简单直接但明显有优化空间。我们来推演一遍优化过程。如果n可以被某个大于sqrt(n)的数a整除那么商b n / a必然小于sqrt(n)且n也能被b整除。所以判断范围只需要缩小到sqrt(n)就足够了。import math def is_prime(n): if n 2: return False if n 2: return True if n % 2 0: return False limit int(math.isqrt(n)) for i in range(3, limit 1, 2): if n % i 0: return False return True注意几个细节首先处理n 2的情况因为0和1不是素数其次单独处理n 2这是唯一的偶素数然后跳过所有偶数直接从3开始按步长2遍历。这个版本比朴素写法速度翻了几倍。模拟一遍判断101是否为素数时limit 10循环只需要检查3, 5, 7, 9四个数而朴素写法要检查100个数。这就是算法优化的直观体现。这道题贯穿的核心思维是理解“前置条件判断”“减少无效计算”的思想放在真实工程里就是你对数据库查询加索引、对接口做缓存的同款逻辑。2.5 字符串反转与回文判断不可变性的坑字符串处理和数组是“简单卷”里最容易踩坑的板块。以回文判断为例题目要求判断一个字符串正读和反读是否相同比如level、上海自来水来自海上。Python 里最简单的方式是切片反转def is_palindrome(s): return s s[::-1][::-1]这行代码干了一件什么事它利用了 Python 切片的step -1参数表示从最后一个字符向前遍历整个字符串得到反转后的新字符串。这个写法非常简洁但新手往往看不懂所以我建议刚入门时先写一个显式的双指针版本def is_palindrome(s): left, right 0, len(s) - 1 while left right: if s[left] ! s[right]: return False left 1 right - 1 return True这个版本更容易理解而且时间复杂度同样是 O(n)。在 C 中字符串是可变的但很多人写反转时会忘记用一个临时变量导致交换失败char temp s[left]; s[left] s[right]; s[right] temp;这里有一个我踩过的坑Python 字符串是不可变对象你没法直接修改某个位置的字符比如s[0] a会直接报 TypeError。所以你要么用列表把它拆开要么用切片生成新字符串。这类练习看起来不起眼但它会在你之后做数据处理时反复提醒你“不可变对象”和“可变对象”的本质区别。顺带说一个延伸小技巧如果你要做“忽略大小写、忽略标点”的回文判断可以在比较之前统一转换s .join(ch.lower() for ch in s if ch.isalnum())先用isalnum()过滤掉非字母数字的字符再统一转小写。这个写法在 LeetCode 的 125 题里直接就能用但它本质上也属于“简单卷”的范畴。3. 实操现场完整走一遍从题目到上线的流程3.1 环境与语言选型Python还是C很多新手会纠结“我该用 Python 还是 C 来刷简单卷”。我的建议是以 Python 为主有条件的话用 C 复练一遍核心题。Python 的优势是语法简洁、写起来快能让你把精力集中在逻辑本身。C 的优势是类型系统严格能逼你理解内存分配、引用的概念。我在带新人时见过一个现象只学 Python 的人往往对“变量类型”没什么概念反过来只学 C 的人又容易被指针和内存绊住写起业务代码来上手慢。所以我的实战方案是“双轨制”。第一遍用 Python 快速过完所有题目理解核心逻辑第二遍挑 5~6 道经典题用 C 重写感受不同的语言约束。下面这条命令可以快速准备好 Python 环境# 推荐用虚拟环境管理依赖避免污染系统 Python python -m venv classic-practice source classic-practice/bin/activate pip install pylintpylint是 Python 的代码检查工具会帮你揪出变量名混乱、缩进错误、无效语句等基础问题。我在练习阶段就习惯每写完一道题跑一次 lint久而久之代码风格就规范了。C 这边我推荐用g直接编译运行g -stdc17 -Wall -Wextra main.cpp -o main ./main-Wall -Wextra会开启几乎所有编译警告。新手写 C 最常见的坑就是忽略警告结果变量未使用、比较有符号无符号整数等隐患一直留着等代码规模大了才爆雷。3.2 一个完整例子猜数字游戏的开发过程选一个综合题来演示完整流程。猜数字游戏的规则很简单程序随机生成一个 1 到 100 的整数玩家输入数字程序提示“大了”“小了”或“猜对了”直到猜中为止。这道题覆盖了随机数、输入处理、循环控制、条件判断和退出条件设计非常适合作为简单卷的“综合应用题”。第一步先写伪代码。这一步很多人会跳过但我强烈建议新手不要跳因为伪代码能帮你把逻辑理清再动手大幅减少写代码时的思路混乱。1. 随机生成 1 到 100 的整数 target 2. 进入无限循环 3. 读入玩家输入 guess 4. 如果 guess 大于 target提示“大了” 5. 如果 guess 小于 target提示“小了” 6. 如果 guess target提示“猜对了”退出循环 7. 结束第二步把伪代码翻译成 Pythonimport random target random.randint(1, 100) while True: try: guess int(input(请输入你的猜测1-100)) except ValueError: print(输入无效请输入一个整数) continue if guess 1 or guess 100: print(请输入 1 到 100 之间的数字) continue if guess target: print(大了) elif guess target: print(小了) else: print(猜对了游戏结束) break注意我在输入处理上加了两个判断一个是try-except来捕获非数字输入另一个是范围检查。这两个细节是新手最容易漏掉的。如果你不处理异常输入用户随便输入一个 “abc” 程序就会直接崩溃。第三步跑一遍完整流程。我先输入一个 50程序提示“小了”再输入 80提示“大了”然后 65、70、72最后 73 猜中。整个过程 5 次就结束了。这里我特意测试了边界输入输入 0、101、abc程序都能友好地给出提示而不是崩溃。一个“能跑”的简单程序和“能正确处理各种异常情况”的程序差别就在这里体现出来了。3.3 测试用例怎么设计别只看正确答案做简单卷练习时很多人会陷入“程序跑出正确答案就草草收工”的误区。我建议你每做完一道题都额外设计几组测试用例尤其是边界值和异常值。以闰年判断为例至少要测这四组数据输入预期输出实际测试目的2000是闰年能被400整除的情况1900不是闰年能被100整除但不能被400整除2024是闰年能被4整除但不能被100整除2019不是闰年普通非闰年我通常在本地写一个简单的断言脚本来批量验证assert is_leap(2000) True assert is_leap(1900) False assert is_leap(2024) True assert is_leap(2019) False print(所有测试用例通过)这个习惯虽然简单但它训练的是“测试思维”也就是验证程序正确性的系统性方法。真实工程中的单元测试框架比如 pytest、JUnit本质上就是在做同一件事只是规模更大、自动化程度更高。你如果在简单卷阶段就养成了“多测几组边界值”的习惯后续写任何代码都会下意识地多想几个场景。4. 刷完简单卷之后这些基础怎么帮你闯进真实工程4.1 从练习题到工程代码思维要换挡刷完简单卷你已经掌握了语法和基础逻辑但离写工程代码还有一道坎思维的换挡。练习题里的世界是理想化的输入固定、输出明确、没有网络抖动、没有并发冲突真实工程则充满了不确定性。举个例子你在练习题里写的“输入两个整数求和”对应到真实工程就是“接口接收用户提交的两个参数经过参数校验、格式转换、业务处理、异常捕获最后返回结果”。这两者之间差的不是代码量而是工程思维。简单卷阶段你要刻意练习的是“防御性编程”的雏形——比如前面提到的输入异常处理、边界值检查这些习惯会自然迁移到工程代码里。很多人问我是不是刷完简单卷就能学 Spring Boot、能写 Web 服务了我的答案是能但要把姿势摆对。简单卷帮你打好了语法和逻辑的地基你可以去学框架、学数据库但一旦遇到卡壳多半要回到基础的逻辑能力上找问题。我见过太多人报错后第一反应是去问 ChatGPT而不是先看报错信息和数据流。这不是工具的问题是基本功还不够导致他没能力自己排查。4.2 经典练习和异步、并发、AI编程的真实交点再往深一层看经典练习中培养的能力会和很多热门技术产生真实交点。异步编程的核心是事件的发起、等待和回调你必须在脑子里维护多个任务的状态。这跟你在“数组逆序”里维护多个指针的状态、在“斐波那契”里维护前后项状态的逻辑其实是一回事。状态管理能力不过关的人写异步代码会特别痛苦动不动就乱成一团。并发编程也是类似的逻辑。两个线程同时操作同一个变量、导致数据不一致本质上你处理的就是循环里i被多线程改乱的场景。经典练习里反复训练的对变量生命周期和状态的敏感度在这里会派上大用场。至于眼下火热的 AI 编程我更想说两句。用 Cursor 这类 AI 编程工具确实能让你几秒钟生成一个冒泡排序或者给你解释一段复杂代码的含义。但工具能帮你写代码没法替你建立“判断对错”的直觉。你依然需要靠自己的基本功来理解运行结果是否正确、边界条件是否覆盖、性能是否合理。所以我的建议是新手前期一定要手写简单卷至少把核心题做一遍等你能流畅手写这些题了再拥抱 AI 编程工具效率才会翻倍。4.3 给新手的后续路线图简单卷刷完下一步往哪走我按我的经验给你画一条参考路线补数据结构基础数组、链表、栈、队列、哈希表、二叉树每学一个就配合练习题巩固。开始刷基础算法排序、二分查找、双指针、递归回溯这些是面试和工程里最常见的算法类型。学一门主攻语言深入如果你做 Web 后端把 Python 的协程、装饰器、生成器搞明白如果做底层把 C 的内存模型、容器实现搞清楚。上手一个小型工程做一个命令行版本的工具、爬虫、博客系统把语法和能力用在一个实际项目里。在这个基础上再去碰框架、分布式、异步编程这些进阶话题你会发现很多概念都变得更容易理解。这个路线不是唯一解但它是我带过不少新人验证过的路径。关键是顺序不能乱基本面没打牢直接冲高阶话题大概率会摔跟头。5. 踩坑记录与排查技巧实录5.1 新手最容易犯的五个典型错误我在指导新人刷题时观察到一些反复出现的高频错误。整理成表格方便你对照自查错误类型典型表现解决方案无限循环循环跑不停程序卡死检查循环条件是否会被更新循环变量是否在循环体里改变边界错误输出结果差一个数循环少跑一遍用边界值代入验证比如i0、in分别测试一遍变量覆盖中间结果被后续操作覆盖注意赋值顺序必要时引入临时变量类型混淆字符串和数字做运算条件类型不匹配明确变量类型用int()、float()显式转换忽略异常输入输入非法字符导致程序崩溃用try-except捕获异常或用条件判断过滤非法值举一个我实际见过的例子有个新手用range(1, n)遍历数组结果发现最后一个元素永远访问不到。当我让他把n代入具体值跑一遍时他马上发现range(1, 5)实际生成的是1, 2, 3, 4并不包含 5。这种边界问题最好的排查方式就是代入具体数值而不是盯着代码发呆。5.2 快速排查问题的三个习惯刷题时遇到报错不可怕可怕的是不知道怎么排查。我总结了三个习惯新手可以照着练。第一个习惯是“从报错信息开始”。很多人一看到一大段报错就慌了直接复制到搜索引擎或问 AI其实报错信息里已经包含了关键线索——第几行出错、什么类型错误、变量名是什么。你要做的是先仔细读一遍报错信息再结合代码定位问题。第二个习惯是“二分定位”。如果整个程序跑出来不对不要从头到尾逐行检查而是先确定出错的大致范围。比如在循环前后分别打印一行标记在关键变量处打印当前值很快就能锁定问题出在循环内部还是外部。这个过程就像排查网络故障一样先分段隔离再精确定位。第三个习惯是“把代码拆到最小可复现”。我在让新人求助前都会要求他把代码精简到 10 行以内、还能复现问题这样既方便别人帮他看也经常在精简的过程中自己就发现问题了。这个习惯在真实工程里同样有效保留最小复现样本是提 Bug 工单的基本素养。5.3 我的个人实操心得最后分享一些我在练简单卷和带新人过程中的体会。我强烈建议你为每道题建立一个“错误日志”。不要只在程序跑通那一刻兴奋而是把踩过的坑记录在文档里比如“忘记处理空字符串”“数组下标越界”“浮点数比较不准确”。过两周回头翻看你会发现这些错误高度重复而记录本身就是在帮你复盘和固化经验。这个习惯我保留至今只不过载体从笔记本换成了 issue 系统。另一个体会是手写代码的能力不能丢。即使你已经用了很久 AI 编程工具我仍然建议你每周手写一道经典题比如用笔在纸上写一个冒泡排序或者直接在编辑器里不查资料写出一个递归函数。这能帮你持续保持对基础逻辑的敏感度。我见过一些工作两三年的开发者一旦离开 IDE 提示和自动补全连for循环都写得磕磕绊绊这种能力退化是很可惜的。每个人练简单卷的方式都不完全一样但你投入在这套基础练习上的时间绝对会以某种形式在未来回报你。它是你走进编程世界最稳的一块跳板也是你未来回头看时最值得庆幸的一段基本功积累。
返回列表