
你是不是也有过这样的瞬间——刷短视频时平台好像比你自己还懂你想看什么打开外卖 App推荐的餐厅恰好正中你的口味用导航软件它总能避开拥堵给你一条最顺的路。这些“懂你”的背后其实是同一种东西在默默工作算法。这个词如今频繁出现在各种新闻、技术文章和聊天里但真要问一句“什么是算法”很多人又说不清楚。这篇长文就想把这个既基础又关键的概念掰开揉碎从最根源的定义讲起再到我们身边无处不在的应用最后聊到普通人怎么上手学习尽量让零基础的读者也能彻底搞懂并且知道学了之后它能用在哪儿。我会刻意避开那种“教科书式”的拗口定义而是从一个从业者日常理解的视角出发用生活里最熟悉的场景做类比。读完之后你再看到“算法”两个字不再会觉得它是高深莫测的玄学而是像“菜谱”“地图路线”一样具体的东西。更重要的是你还会看到一套评估算法好坏的方法、几个最核心的经典算法范式以及一条零基础就能启动的学习路径。1. 算法到底是什么从一个菜谱说起1.1 别背定义先看一个“做菜”的例子要理解算法我建议先把那些教科书定义放一边。你想我们做一道菜是不是得有个明确流程准备什么食材、先放油还是先放盐、炒多久、火候多大。哪怕是一碗简单的西红柿炒鸡蛋步骤也可能不止一种有人喜欢先炒蛋盛出来再炒西红柿有人直接混在一起炒。两种做法最终菜都能吃但口感、耗时、颜值各不相同。这套“明确流程”就是算法。计算机里说的算法本质上和做菜流程是一类东西它是一个明确、有限、可执行的步骤集输入某些数据经过一步步操作最终得到我们想要的输出结果。比如你给程序输入一堆数字算法会告诉你这些数字从小到大怎么排你给导航输入起点和终点算法会告诉你走哪条路最近。生活里还有更多例子。以前查纸质字典想要快速找到“算法”这个词你不会一页页从头翻而是利用拼音或者部首先去定位再小范围查找这就是一种查找算法。整理一副扑克牌有人按从小到大顺序一张张插到已排序的位置有人先按花色分堆再每堆排序这些也都是排序算法的雏形。可以说算法并不神秘它就是一种“处理问题的思路”被结构化的结果。1.2 算法的五个基本特征既然算法是一套步骤集它就必须满足几个基本特征否则计算机没法执行我们也没法复用。我总结为五条有穷性步骤必须在有限次数内结束不能陷入死循环。比如“不断往左走直到看到红色房子”这个描述如果那条街根本没有红色房子就永远走不完这不是合格算法。确定性每一条步骤的含义必须确切不能有歧义。“放少量盐”对人可以但计算机理解不了“少量”你需要说“放3克盐”。可行性每一步操作都必须在现有条件下能够实现。让计算机“随机猜一个最优结果但是必须刚好正确”这就不可行。有输入有零个或多个输入数据。比如一个“获取当前时间”的算法可以没有外部输入。有输出至少有一个输出否则没人知道它到底干了什么。这五条里“确定性”和普通人生活关联最紧密。你想想日常跟人协作分配任务最怕的就是对方听了个大概理解出两三个版本。算法的“确定性”就是要求在沟通前把规则彻底讲死避免歧义。这也是写代码和做人做事共通的地方。1.3 为什么算法不是“代码”有个常见误区算法等于代码。我用个比喻解释算法是剧本代码是演员的演出。同一个剧本可以用普通话演可以用粤语演甚至翻译成英语演核心情节不会变。同样的道理同一个算法可以用 Python 写、用 Java 写、用 C 写每种语言只是不同的“表达方式”算法本身是独立于语言的思路。举个例子“从一堆数里找最大值”这个算法思路就是先假设第一个数是最大值然后拿它和后面的数逐一比较遇到更大的就更新。这个思路用 Python 写大概三四行用 C 写七八行但核心逻辑完全一样。你学会的是思路语言只是顺手表达的工具。这个观念特别重要很多人一开始学编程容易陷入死记代码的误区。一旦想明白“代码只是算法的载体”学习重心就会从“背语法”转向“练思维”后者才是解决问题的真正能力。2. 如何评价算法的好坏效率这件事很重要2.1 从一根针里挑出最长的针现在我们知道了算法是什么但现实里解决同一个问题常常有多种不同算法。就好比从一个针线盒里找出最长的一根针。最笨的办法是把所有针一根根排开用尺子量一遍记录每次新的最大值。这个办法一定能得到正确结果但如果有一万根针你得量一万次。聪明一点的办法呢先用手大致摸一遍把特别短的排除掉只对剩下的几十根仔细量。如果这些针的长短分布很极端这种“先粗筛再细量”的思路就会快很多。计算机领域也一样解决同一个问题可以写出思路完全不同的算法。但作为工程师我们不能只满足于“能跑出结果”的算法我们还要关心这个算法够不够快、吃不吃内存。这就是算法分析的核心内容——复杂度的考量。2.2 时间复杂度衡量“步数”而不是“秒数”衡量一个算法快慢直接的指标当然是运行时间。但同样一个算法在一台破旧电脑上可能要跑5秒在新款旗舰手机上可能只要0.5秒这个绝对时间没法公平地评价算法本身的好坏。于是计算机科学家提出时间复杂度的概念它不是看具体的秒数而是看算法执行需要的“基本操作次数”随数据规模如何增长。这里的数据规模通常用n表示。比如上面找最长针的问题如果有n根针每根针都要量一次操作次数大约是n我们记作O(n)读作“大O n”。如果有一个算法需要两层循环每个元素都和其他所有元素比较一次那么操作次数大约是n的平方记作O(n²)。这里要特别说明大O符号描述的是“增长趋势”不是精确次数。O(n)表示操作次数和输入规模成正比输入翻10倍耗时大约也翻10倍O(n²)表示输入翻10倍耗时大约翻100倍这个差距越到后面越恐怖。用生活场景类比最直接。假设你有100条数据要处理O(n)算法大概要执行100步O(n²)算法要执行10000步现代计算机都秒完。但数据变成1亿条呢前者1亿步后者就是10的16次方步后者会跑到天荒地老。这也是为什么在实际的大数据场景里算法选型这么重要——差的算法数据规模一上来就彻底扛不住了。2.3 空间复杂度内存不是无限大的免费仓库时间复杂度之外还有空间复杂度它衡量的是算法在运行过程中额外占用的内存规模。有些算法特别快是因为它预先建了很多临时数据牺牲了内存换来了时间有些算法内存很省但跑得慢一些。多数场景下我们需要在时间和空间之间找一个平衡点。还拿找最长针举例。笨办法边量边记录只需要记住当前最长的针占的空间是固定的记作O(1)也就是常数空间。但如果我要求“把所有针按长度排序后输出”那最朴素的做法是把它们全部存到新列表里排好内存占用随n增加就是O(n)空间。现实中的移动设备内存有限如果写一个图片处理算法只顾时间不管内存很容易导致手机 App 闪退。面试和实际项目中也常会问你这个算法空间复杂度能不能降一降很多人只顾着快忽略了内存占用结果发布到大流量环境里吃满了内存线上事故就是这么来的。2.4 最好、最坏与平均情况另一个必须知道的点是同一个算法在不同输入下表现可能天差地别。例如“快速排序”这个著名算法大多情况下非常快复杂度是O(n log n)但如果输入数据刚好是几乎有序的而你的实现又选了边界值做基准它可能退化到O(n²)的表现。因此算法评估通常区分三种情况最好情况输入恰好是算法最喜欢的形态比如已经排好序它走最少步骤。最坏情况输入造成最大工作量比如恰好逆序。平均情况所有可能输入的综合期望表现。很多人看算法资料只盯着“平均复杂度”忽略最坏情况。但实际系统开发里我们往往要重点防最坏情况因为一旦线上出现极端输入导致性能坍塌用户感受到的就是卡顿和超时。“别让你的算法在最坏情况下坍塌”这是我做技术这几年最深的一句心得。3. 几类改变世界的经典算法思路前面讲的是评价角度现在我要分享几种具体但影响深远的经典算法思路。它们不只是考卷上的题目很多互联网产品背后都靠它们支撑。3.1 排序与查找信息世界的基建工程排序和查找是计算机世界最基础、也最无处不在的两类算法。我们打开通讯录看到按拼音排好的人名、电商平台按价格排序商品背后都是排序算法在工作。最经典的排序算法包括冒泡排序、插入排序、归并排序、快速排序等。其中冒泡排序对学生来说最好理解重复交换相邻的逆序元素最大的像气泡一样慢慢“冒”到末尾但它的效率不高复杂度是O(n²)数据一大就吃力。快速排序则用“选基准、分区、递归处理”的思路把效率通常提到O(n log n)成为工业级最常用的排序方案。查找算法里最值得了解的叫二分查找。前提是数据已经有序。它的思路就像猜数字游戏你心里想一个1到100的数我猜50你说大了还是小了每猜一次就能排除一半的范围。二分查找每次也抹掉一半候选所以即使在海量数据里它也能极快地定位目标。很多年前我曾参与过一个字典匹配系统的优化原始方案是把几百万词条全部加载到内存里逐个匹配结果内存和耗时双双爆炸。后来我们把词条排序并改用二分查找耗时几乎降到原来的千分之一内存占用也大幅减小。这就是“排序二分查找”这套基础组合的威力。3.2 递归与分治把大问题拆成自己能解决的小问题递归的特点是函数调用自己想象俄罗斯套娃打开一个里面还有一个小一号的娃娃一直开到最小那个。在处理某些问题上这个思路非常自然。比如计算一个文件夹占用的总大小你可以把问题定义成“本文件夹的大小 每个子文件夹的大小”而每个子文件夹又继续按同样规则拆解直到某个文件夹里没有子文件夹。分治法则把递归思想用到了极致把一个巨大的问题拆成几个规模较小的独立子问题分别解决后再把结果合并起来。归并排序就是分治的典型把一个无序数组一切两半两半各自排好序最后把两半有序序列合并成一个整体有序序列。这个思想在生活里也能用。比如清洗一座大楼的所有窗户你不会一个人从一楼擦到顶楼而是把大楼按楼层分给多个小组每小组独立擦完自己负责的楼层最后统一检查验收。思路一样拆解、并行、合并。3.3 动态规划记住算过的结果别重复劳动动态规划这个名词听着高大上核心却特别朴素把一个大问题拆成有依赖关系的子问题并且把子问题的结果存下来避免重复计算。经典例子是爬楼梯问题假设一次可以走1级或2级台阶到达第n级有多少种不同走法如果我们从第0级开始要想到达第n级最后一步可能来自第n-1级也可能来自第n-2级因此走法总数等于两者之和。按这个思路从n0递推下去每一级的结果只依赖前两级完全不需要递归树里那种大量重复计算效率极高。动态规划在现实里最常见的影子之一就是地图导航里的最短路线规划。从一个路口到另一个路口最优路线可以拆成“到中间某个路口的最优路线 最后一段路”大量中间结果被反复重用这样才能在几百毫秒内给出路线。要掌握动态规划关键是识别“重叠子问题”和“最优子结构”。说实话这并不容易但一旦跨过门槛很多硬核优化问题会豁然开朗。3.4 贪心算法每步都选当下最好的但不一定全局最优贪心算法的策略很简单每一步都取当前状态下最有利的选择不回头、不纠结后路。用一句话说“只顾眼前利益”。在一些特殊结构的问题里贪心反而能直接拿到全局最优解。比如经典的找零问题如果货币面额是1元、5元、10元、20元、50元、100元要找几块钱时每次都挑不超过剩余金额的最大面额最终拿到的纸币张数就是最少的。但贪心不是万能金钥匙。有些问题里每步最优组合起来并不是全局最优。典型的例子是背包问题背包容量有限每件物品有自己的重量和价值想装下总价值最大的一组物品。简单贪心往背包里先塞“单位重量价值最高”的物品最后留下的空间未必合适得到的组合往往不如动态规划算出的结果。这点带给我的职场启示也很大。做技术方案不能只看眼前最顺的一步要把后期的依赖和约束放一起评估。很多“短期最快”的选择放在整个项目周期里就是埋坑。4. 算法在现实世界的渗透你每天都被算法环绕很多人觉得算法是程序员面试题离普通生活很远。恰恰相反现代生活已经快被算法包围了。4.1 信息分发为什么你越刷越停不下来短视频平台和资讯 App最核心的技术就是推荐算法。它会记录你看了什么、划掉什么、在哪个视频停留了多久再对比所有用户的观看行为找出和你口味相似的人群把他们喜欢的其他内容推荐给你。这背后用到了协同过滤、矩阵分解、深度学习排序模型等一堆技术但核心目标一致猜测你对每个内容感兴趣的概率把概率最高的内容排在最前面。所谓“刷到停不下来”背后往往还叠加了强化学习等技巧算法在实时试探你的即时反应不断调整内容流。理解这里的原理后你就会明白一个朴素的道理你看到的世界是算法根据你的历史选择塑造出来的。这种“信息茧房”效应也是算法副作用的热门话题。4.2 路线规划与物流调度先有算法后有外卖你在外卖 App 下单系统背后要做的事情非常多。首先附近有哪些骑手、谁顺路、谁手里单少这是配送调度算法其次取餐和送餐路线怎么排列最优这是路径规划算法最后平台还会预测出餐时间和送达时间动态调整接单范围。我们公司曾经做过一个简化版物流调度系统光是“为30个配送点安排最优路线”这个问题最朴素的枚举法就需要算 30 的阶乘种可能这个数字大到你根本无法单靠暴力计算得到答案。实际系统只能用启发式算法或者近似算法在可接受时间里找到接近最优的方案。由此可见算法不是“锦上添花”而是一套大系统的血管。4.3 搜索与排序在万亿网页里捞出你要的那一页搜索引擎看起来是“敲关键词然后出结果”背后的难度却超乎想象。搜索引擎要把全网网页抓下来建立倒排索引像书后面的关键词索引一样记录每个词出现在哪些网页用户输入查询后算法在索引里查找相关网页再通过网页排名算法如 PageRank 这类思路对结果排序把“重要的、相关的”排前面。网页数量级达到数十亿甚至更多没有倒排索引和高效的排序、检索算法一切都不可能。有趣的是你平时用 Excel 里的“排序筛选”原理上也是同一套算法体系。小到一张表格大到整个互联网排序与检索算法永远在支撑着信息世界的秩序。4.4 数据压缩与加密算法保护着你看不见的角落看视频、传文件时谁都希望数据量小一点、安全一点。数据压缩算法的思路是去掉冗余把信息用一种更紧凑的方式表达——好比写文章时把“中华人民共和国”简写成“中国”收到后再展开回全称。加密算法则是“把明文按密钥变换成密文”没有密钥的人在计算上几乎不可能还原原文这是现代互联网支付、聊天、登录等一切安全行为的基石。这两类算法平时完全无感但影响巨大。没有压缩算法你手机的高清视频根本传不动没有加密算法在线支付就是裸奔。它们属于“用的时候不知道但出问题时才知道有多重要”的典型。4.5 算法滥用带来的代价与思考算法不是只有好处它也有代价和风险。推荐算法容易让人上瘾大数据杀熟可能让老用户看到更高价格人脸识别算法可能因为训练数据偏差产生误判。我们使用算法时也要意识到它的局限性。算法是人类设计出来的天然会继承设计者的偏见和训练数据的偏差。透明性、公平性、可解释性这些伦理话题在未来会越来越重要。任何从业者都不该只沉浸在技术快感中而忘了技术最终是服务于人的。5. 零基础怎么学算法一条可行的路径5.1 学习算法必须掌握的数据结构基础想把算法学好数据结构是绕不开的地基。数据结构可以理解为数据的组织方式同样的数据组织方式不同操作效率就完全不同。我建议按这个顺序打基础数组和字符串最基础的数据组织方式。数组像一排连续的储物柜按下标可以直接取东西字符串是字符组成的数组处理文本离不开它。链表像一列火车每节车厢既载货又连着下一节。它的优点是可以快速插入删除节点但按下标查找比数组慢。栈和队列栈像一叠盘子后放上来的先取走这叫后进先出队列像排队先进去的先出来这叫先进先出。它们是很多复杂算法的基础构件。哈希表相当于一个超级字典给你一个键几乎瞬间能找到对应的值。缓存系统、数据库索引里广泛用到它。树和图树就像公司组织架构根节点是我们下面分支延伸。二叉树、二叉搜索树都是高频考点图更像地铁线路图点与点之间有关联路线规划类算法都在图上进行。顺序上我推荐先数组、链表、栈、队列和哈希表再进入树和图。基础不牢时去啃高级算法很容易学成一锅粥。5.2 分阶段刷题从“看题没思路”到“套路自动浮现”有了数据结构基础下一步就是实践。主流做法是去在线判题平台刷题用练习来巩固思路。但刷题不能瞎刷我建议分阶段阶段一按专题突破。比如先专刷“数组”类题熟悉双指针、滑动窗口这些常见技巧再换“链表”专题练习反转、合并、判环。这个阶段不求多但求每个专题的核心套路都过一遍。阶段二混合模拟。把几个专题混在一起练看到题目后自己判断“这题属于什么类型该用什么思路”的能力。很多新手在专题阶段已经会做一旦混合马上露怯这很正常多练就好。阶段三限时实战。模拟面试场景给自己二十分钟到半小时一道题即使做不出来也强行进入讲思路状态。这个过程很痛苦但对真实求职帮助极大。我见过太多人一上来苦学几个月理论知识题库一道没刷结果面试手撕代码直接卡壳也见过人疯狂刷题几百道却不复盘同类型题换个马甲又不会了。刷题的正确姿势是“动脑 总结 重做错题”不是堆数量。5.3 学算法的常见误区与避坑建议只说路径不够我还想单独盘一盘新手最容易踩的几个坑只学不练算法是思维运动光看不做永远学不好。看完一个算法必须亲手复现一遍哪怕照着代码敲一遍都比只看有效十倍。死记代码很多同学背模板式地记下快排代码但换个问法就不会了。正确做法是画递归树图、手动模拟执行流程把每一步含义吃透。会画图就说明你真懂了。过分追求难题怪题竞赛级难题对日常工作帮助有限反而容易打击信心。性价比最高的学习区间是高频的基础题和中档题。忽视复杂度分析很多人的代码能跑但一问复杂度就懵。掌握复杂度分析才能判断一个解法在真实数据量下是否可用这也是面试必问。急于求成算法能力提升是明显的非线性过程经常会出现一两周毫无进展、突然又开窍的情况。心态稳一点坚持复盘最重要。5.4 算法思维对生活的正面溢出效应最后说点个人体会。学算法给我带来的不只是写代码能力更是一整套解决问题的思维框架。遇到复杂任务我会下意识拆成子任务分别攻克再合并结果这就是分治思维设置工作计划时我会识别哪些环节是重复劳动想办法只算一次、重复使用结果这就是动态规划思维面临多选一时我会先判断当下的贪心方案到底有没有长期优势避免短视决策。这种思维方式的转变是算法学习最大的隐藏收益。哪怕你以后完全不写代码学过算法后你的逻辑链条会更严密面对复杂问题时不会眉毛胡子一把抓而是先分析、拆解、排序找出关键入口。这些能力会跟着你走很远。我个人在实际操作中的体会是理解算法最好的方式永远是自己动手画一遍过程。拿一张纸写下几个数一步步模拟算法怎么移动、怎么比较、怎么交换直到你能在纸上把完整流程复现出来。刷题遇到卡壳时先别急着看题解而是画图推演一遍大多数时候答案就会自己浮现出来。这种“先手推、再码代码、最后总结套路”的学习节奏适合绝大多数零基础的人。说到底算法不是门槛高不可攀的学问它就是一套“把事做对、把事做好”的思考方法。希望你读完这篇长文不只是记住了几个名词而是真正确立起一种意识以后无论遇到多复杂的任务都可以把它拆成看得见、摸得着的步骤再一步步去优化、去实现。这是算法带给每个人最宝贵的礼物。