晚上十一点多。电脑屏幕的光直往脸上扑,刺得眼睛发酸。硬盘里那一堆零碎文件,我还在吭哧吭哧地建目录,硬往几个主格子里塞。图啥呢?真跟给人生做拓扑排序似的,非得把节点卡得死死的。生怕哪天要找个东西,翻了半天还在原地打转。正烦着,手肘一拐,碰倒了书架最底层的一本旧书。掸了掸灰,随手翻开。好家伙,作者压根不拿大O推演算法复杂度,直接上代码,跑时间测试。嘿,这事儿大概就是这么个意思。

大O这词儿,听着确实让人踏实。它拍着胸脯跟你保证,指条理论上的近道。管你数据量多大,排序查找,都能掐着某个刻度走。可咱们过日子,真靠它算账吗?我猜未必。挑专业,换城市,跟谁好,跟谁分,每天几点起几点睡……全在脑子里拉条复杂度曲线。怕走岔道。怕掉进O(n²)的泥坑。怕那些说不清的变数,咔嚓一下把架子掀了。总琢磨着,开局定死,路线画细,人生就能按着既定的时间复杂度,稳稳当当往下走。拉倒吧。这种“算无遗策”的执念,多半是还没被现实捶打过的人,给自己打的鸡血。现实里,哪有什么绝对的最优路径?

但代码跑起来,是另一码事。它不跟你扯理论边界。直接把程序扔进生产环境,跑一跑,看看到底吞了几秒。缓存命中率差那么几个百分点,内存碎片没对齐,甚至那一哆嗦的网速波动,都能让纸面上的“最优”,直接卡出转圈菊花。日子估计也这德行。你以为选对了赛道,结构搭得再漂亮,真钻进去才发觉,那些根本写不进伪代码的摩擦——突然砸下来的变故,旁人随口一句的期待,自己某天突然变卦的心情——全在后台静默地偷走运行时间。这事儿未必是坏事。它可能只是系统在提醒你:别光看理论峰值,得看实际负载。

说实在的,我早年也死磕“最优解”。刚工作那阵,恨不得把一周七天塞进日程表。写动态规划似的,把每个阶段的子问题都抠得严丝合缝。后来赶上一个项目延期。连熬三个大夜,才咂摸出味儿来:再精密的算法,也算不进人心的弯弯绕,更算不进身体的垮掉。挤在地铁里,看窗外倒退的灯火,我突然觉得,那些咱们故意绕开的“冗余步骤”,那些看着白费的发呆和扯闲篇,没准根本不是浪费。那是系统自带的冷却机制。打那以后,我慢慢松了绑。不再非要拿生活去套教科书里的标准实现。随它节点碰撞。随它链表断了再接上。反正跑通了,才算数。

书里聊到散列表,扯到了冲突处理。理论上再完美的映射,落到实际里,总会撞见两个键抢同一个位置。这时候得退半步。拿开放寻址或者链地址法去将就。我跟人打交道,慢慢也悟出点这道理。哪有什么天生严丝合缝的搭档?全是在一次次错位里,摸索出彼此都能住下的地方。有时候退一步不算输。只是换了条寻址的路。概率算法里也常念叨,别死盯每一步都绝对正确。多试几次,整体结果慢慢往“凑合”上靠就行。当然,这话也不是万能药。要是核心逻辑一开始就写歪了,跑再多轮也是白搭。但生活里的不少选择,大抵也是这个理儿。

合上书,外头天都快亮了。硬盘里的文件夹还没捋顺,我随手新建了个“临时”,把剩下的全一股脑儿扔了进去。管它呢。人生本来就不是为了跑通个完美算法。而是扔进真环境里,看看自己到底能装下多少东西,能硬扛多久。有些路,压根不用提前算复杂度。迈进去。测一测。心里就有数了。