问题定义清晰、输入输出明确——最有效
算法选型框架最擅长处理的问题有三个特征:输入和输出可以精确定义、正确性可以客观验证、计算量是核心瓶颈。
经典场景:路径规划(输入是图和起终点,输出是最短路径)、排序和搜索(输入是数据集,输出是排序结果或搜索目标)、字符串匹配(输入是文本和模式,输出是匹配位置)、组合优化(输入是约束条件,输出是满足约束的最优解)。
在这些场景里,Skiena 的框架——建模、确认复杂度、查目录选算法、实测验证——直接可用。
两类问题经常被误认为算法问题
瓶颈在 IO 不在计算的问题。 数据库查询慢、API 响应慢、文件处理慢——花时间优化算法的时间复杂度可能没用。实际的瓶颈在磁盘 IO、网络延迟或数据库索引。把 O(n log n) 优化到 O(n) 在 IO 是瓶颈的场景里几乎没有体感差别。先用 profiler 确认瓶颈在哪里,再决定是优化算法还是优化系统。
问题定义本身模糊或在变的需求。 "给用户推荐最好的内容"——什么是"最好的"?定义不同,建模方式不同,算法不同。如果产品经理每周都在改"最好"的定义,你花时间选出的算法下周可能就不适用了。这种场景下,选一个"还行"的简单算法加上灵活的参数调整机制,比选一个"最优"的复杂算法更务实。
方法框架会打折扣的三种情况
数据分布和教科书假设不一致。 算法分析通常假设均匀分布或最坏情况。实际数据经常既不均匀也不是最坏——它有自己的分布特征。快速排序在几乎有序的数据上退化成 O(n²);哈希表在键值集中的时候冲突严重。了解数据的实际分布比了解算法的理论复杂度更重要。
系统约束超出了单机算法的范围。 数据量大到单机放不下,需要分布式计算。这时候算法的选择受限于分布式框架支持什么——MapReduce 能跑 word count 但跑不了需要全局状态的算法。分布式环境下的算法设计需要考虑通信成本、数据倾斜、容错机制,这些不在经典算法教科书的覆盖范围内。
性能优化的收益不抵工程复杂度的成本。 把查询从 50ms 优化到 5ms,用了一个复杂的自适应索引结构。代码从 100 行变成了 800 行,只有作者一个人能维护。下次需求变更要改索引逻辑,估工期从 1 天变成 1 周。如果 50ms 对用户体验没有可感知的影响,这个优化的工程账就算不过来。
该停止算法优化的信号
profiler 显示计算时间只占总延迟的 10% 以下。说明瓶颈不在算法——把算法优化到零延迟,整体性能也只提升 10%。把精力放到 IO 优化、缓存策略或架构调整上。
暴力解法在实际数据量下已经满足性能要求。继续优化的收益是"代码更快但已经够快了",代价是"代码更复杂了"。除非数据量预计在半年内增长到暴力法扛不住的地步,否则暂时不需要优化。
你在同一个问题上已经换了三种算法但性能差别不大。说明要么问题的计算量本身就不大(算法选择不重要),要么瓶颈不在算法逻辑上(可能在内存分配、缓存命中、或框架开销上)。这时候需要换一种分析方式而不是再换一种算法。