第66章 算法的时间和空间效率分析
衡量一个算法"快不快、占不占内存",靠的不是跑一次看秒表,而是渐进复杂度——即输入规模 变大时,运行时间/内存如何增长。八级要求"能分析排序、查找、树图遍历、搜索、分治、动态规划等各类算法的时间和空间复杂度,并据此优化"。
66.1 复杂度分析方法
66.1.1 时间复杂度分析方法
- 找出算法中的基本操作:赋值、比较、算术运算等与问题规模强相关的操作。
- 统计基本操作总执行次数,记为函数,为输入规模。
- 简化:仅保留最高阶项、丢弃系数,得到时间复杂度。
算复杂度的三步口诀
① 找"基本操作"(比较/赋值/算术);② 数它随 执行多少次,写成 ;③ 只留最高阶、丢掉常数系数。例:。
66.1.2 空间复杂度分析方法
- 统计程序占用所有存储空间:输入、代码、常量、临时变量、数组、栈等。
- 提取随变化的存储开销,记。
- 简化得到空间复杂度,只保留最高阶项。
66.2 各类算法复杂度分析
66.2.1 排序算法
冒泡排序
- 时间复杂度:平均、最坏;完全有序最优
- 空间复杂度:,仅交换临时变量
快速排序
- 时间复杂度:平均;数组有序/逆序最坏
- 空间复杂度:(递归栈深度),最坏
归并排序
- 时间复杂度:最优/平均/最坏统一
- 空间复杂度:,需要辅助数组存储合并结果
66.2.2 查找算法
顺序查找
- 时间:最好,平均/最坏
- 空间:
二分查找
- 时间:最好,平均/最坏
- 空间:迭代;递归(递归栈)
66.2.3 树遍历(前/中/后序)
- 时间复杂度:,每个节点访问一次
- 空间复杂度:,为树高;平衡树,斜树
66.2.4 图遍历 DFS / BFS
- 时间复杂度:,顶点数,边数
- 空间复杂度:(栈/队列、访问标记数组)
66.2.5 暴力深度/广度搜索(迷宫等)
- 时间:,分支数,搜索深度
- 空间:
66.2.6 分治算法
递推式,归并排序是典型例子,时间。
66.2.7 动态规划
- 一维DP:时间
- 二维DP(LCS、区间DP):时间
- Floyd图全最短路: 空间可通过滚动数组从压缩至
66.3 复杂度等级从快到慢
66.4 真题示例(根据数据范围选算法)
【GESP 八级风格·选择题变形】 某题输入规模 ,时限 1 秒(一般 1 秒约可安全执行 次基本操作)。下列哪个做法最可能超时?
- A. 遍历一遍
- B. 排序后处理
- C. 双重循环
- D. 用优先队列求最值
分析与解答: 估算各做法在 时的操作数:
- A: 次 —— 轻松通过;
- B/C 中的 次 —— 通过;
- C: 次 —— 远超 ,必然超时。
因此选 C。这也是八级"算法优化"章节的核心动机:把 优化到 往往就是"过与不过"的分界线。
附:读代码判复杂度的迷你练习
int cnt = 0;
for (int i = 1; i <= n; ++i) // 外层 n 次
for (int j = 1; j <= n; ++j) // 内层 n 次
cnt++; // 基本操作
双重嵌套、每层都与 相关,总次数 ,时间复杂度为 ;只用了常数个变量,空间复杂度 。
别被"小常数"迷惑
复杂度只反映"增长趋势",不反映确切秒数。但竞赛里常数也不能无限大:同样 ,内层若还带一个 的子过程就会变成 。分析时要把"循环里又套了什么"看清楚。
练习题
说明
下列选择题考查复杂度等级、常见算法复杂度与读代码判阶,参考答案默认折叠,点击"参考答案"展开。
1.(等级) 下列复杂度从快到慢(最优→最差)排列,正确的是?
- A.
- B.
- C.
- D.
参考答案
B。公认顺序:。
2.(排序) 归并排序的时间复杂度是?
- A. 平均 ,最坏
- B. 统一
- C. 平均 ,最坏
- D.
参考答案
B。归并排序无论最好/平均/最坏都是 ;冒泡才是平均/最坏 。
3.(查找) 在已排序数组中用二分查找,时间复杂度是?
- A.
- B.
- C.
- D.
参考答案
B。二分每次把搜索区间减半,最坏比较次数约 ,故 。
4.(读代码) 下面代码的时间复杂度是?
for (int i = 0; i < n; ++i)
for (int j = i; j < n; ++j)
sum++;
- A.
- B.
- C.
- D.
参考答案
C。内层循环次数随 i 从 递减到 1,总次数 。
5.(图遍历) DFS / BFS 遍历一个 个顶点 条边的图,时间复杂度是?
- A.
- B.
- C.
- D.
参考答案
C。每个顶点和每条边都只访问常数次,故 。