北邮研究生课程《算法设计与分析》知识总结 - Part 1
Ch 1. 算法概述
算法五大基本特性
- 有穷性:有限步骤、有限时间内结束,不能无限执行。
- 确定性:每一步操作含义唯一,无歧义。
- 可行性:每一步操作都能实际执行完成。
- 输入:0个或多个输入(问题的原始数据)。
- 输出:1个或多个输出(问题求解结果)。
三类时间复杂度
针对同一问题规模,输入集合:
- 最坏时间复杂度 :所有输入中运行时间最大值。
- 最好时间复杂度 :所有输入中运行时间最小值。
- 平均时间复杂度 :按输入概率加权的平均耗时。
渐近复杂性与五大渐近记号
1. 渐近性态
当,忽略低阶项、常数项、常数系数,只保留最高阶主项,用于比较算法效率。 例:,渐近性态为 ,记作 。
2. 五大渐近记号
| 记号 | 名称 | 数学定义(核心) | 通俗理解 |
|---|---|---|---|
| 大O(渐近上界) | , 时, | 增长慢于/等于 | |
| 大Ω(渐近下界) | , 时, | 增长快于/等于 | |
| 大Θ(紧渐近界) | , | 与同阶(等价) | |
| 小o(非紧上界) | , 时 | 增长严格慢于 | |
| 小ω(非紧下界) | , 时 | 增长严格快于 |
等价简写(选择/判断常考)
五大经典算法设计策略
| 策略 | 核心思想 | 前提/特点 | 典型例题 |
|---|---|---|---|
| 分治策略 | 分而治之:拆分子问题→独立求解→合并解 | 子问题独立、结构和原问题一致 | 归并排序 |
| 贪心策略 | 每一步选局部最优,期望得到全局最优 | 贪心选择性质 + 最优子结构;无回溯 | 活动选择、资源调度 |
| 动态规划 | 记忆化存储子问题解,避免重复计算(以空间换时间) | 重叠子问题 + 最优子结构 | 最长公共子序列LCS |
| 回溯策略 | 深度优先遍历解空间 + 剪枝剔除无效路径 | 约束满足问题、组合问题 | N皇后问题、子集和 |
| 概率策略 | 引入随机因素,求近似解/高概率正确解 | NP难问题、大规模近似计算 | 蒙特卡洛求π |
NP完全性理论
- P类问题:多项式时间可求解的确定型问题(易解)。 例:最短路径(Dijkstra)、排序。
- NP类问题:多项式时间可验证解(不确定是否多项式可解); 特点:找解难,验证解简单;。 例:哈密顿回路。
Ch 2. 递归与分治策略
递归基础
1. 核心概念
- 递归算法:直接/间接调用自身的算法;递归函数:用自身定义的函数。
- 递归两大必备要素
- 边界条件(终止条件):递归出口,保证有限步结束;
- 递归方程:问题的递推定义。
易错点:缺少边界条件会造成无限递归。
2. 递归优缺点
- 优点:逻辑清晰、代码简洁、易理解、便于数学归纳法证明正确性;
- 缺点:调用栈开销大、空间消耗高、调试难度大、运行效率低于非递归。
3. 典型递归函数
-
阶乘函数
-
Fibonacci 数列
朴素递归复杂度:(低效,大量重复计算);最优线性解法 。
-
Ackerman 函数(了解,概念题)
双递归函数,无法转为非递归形式;增长速度极快,其拟逆函数 增长极慢,常规规模下 ,常用于复杂度分析。
经典递归实例
-
全排列问题
思路:依次取每个元素作为首元素,对剩余元素递归求全排列,再拼接结果。
-
整数划分问题
增设辅助函数 :表示正整数 、最大加数不超过 的划分数
原问题划分数:。
-
汉诺塔 (Hanoi) 问题
三步递归思路:
- 将 个圆盘从源柱移到辅助柱;
- 将最底部大盘从源柱移到目标柱;
- 将 个圆盘从辅助柱移到目标柱。
- 移动次数递归式:,解为 ,指数复杂度。
分治策略总述
1. 分治与递归的关系
分治算法天然适合用递归实现;分治拆解出的子问题和原问题结构一致,是递归的典型应用场景,二者常搭配使用。
2. 分治法适用的4个条件
- 问题规模缩小到一定程度后,可直接简单求解;
- 问题可分解为若干规模更小、同结构的子问题(最优子结构);
- 子问题的解可以合并得到原问题的解;
- 各子问题相互独立,无公共子问题(可并行计算)。
- 子问题不独立 → 改用动态规划;
- 无法合并子问题解 → 改用贪心。
3. 分治法标准三步流程
- 分解(Divide):将原问题划分为 个规模均等的子问题(优先均分,提升效率);
- 求解(Conquer):递归求解每个子问题,子问题足够小时直接求解;
- 合并(Merge):将所有子问题的解整合,得到原问题解。
4. 分治算法通用递归复杂度公式
设:问题规模 ,分解为 个子问题、每个子问题规模 ,分解+合并总耗时
5. 对复杂度的影响
- :子问题总规模 > 原问题,复杂度偏高(例:Strassen 原始矩阵乘法);
- :子问题总规模 = 原问题,复杂度适中(例:归并排序);
- :子问题总规模 < 原问题,复杂度最优(例:二分搜索)。
6. 分治 vs 减治法
- 分治法:分解后需要求解多个子问题,再合并所有解(归并排序、最近点对);
- 减治法:分解后仅需求解一个子问题,无需复杂合并(二分搜索、线性时间选择)。
分治经典例题
(一)二分搜索
- 问题前提:有序数组,查找指定元素;
- 核心思路:每次取中间元素比较,舍去一半区间,仅递归处理一个子区间;
- 递归复杂度:
- 复杂度结果:最坏/平均/最好:;
- 应用:红黑树、B/B+树、数据库、操作系统调度。
(二)大整数乘法
用于超长大整数相乘,分治核心:拆分数字 + 减少乘法次数
-
普通分治(4次乘法)
递归式:,复杂度 ,无优化;
-
优化分治(3次乘法)
变形公式减少1次乘法,递归式: 复杂度:,效率提升。
示例
这里以计算 为例,展示如何利用优化分治(仅需 3 次乘法)来高效完成大整数乘法。
设基数 ,总位数 ,半长 。 将两个数按高位和低位拆分:
根据变形公式,我们只需要计算以下三个乘积:
利用 还原出中间项 :
(注:传统算法中 ,结果一致)
将三部分按权重组合:
(三)Strassen 矩阵乘法
- 普通矩阵乘法: 阶矩阵,;
- 标准分块矩阵乘法:8次子矩阵乘法,,仍为 ;
- Strassen 优化(7次乘法) 构造7个中间矩阵,减少乘法次数; 递归式: 复杂度:;
- 特点:大规模矩阵优势明显,小规模常数开销大。
(四)合并排序
- 流程:分解→递归排序左右子数组→合并两个有序数组;
- 合并操作:线性时间 ;
- 递归式:
- 复杂度:最好/最坏/平均均为 ;
- 空间复杂度:(需要辅助数组);
- 特点:分解简单、合并复杂;属于最优排序算法(排序下界 )。
(五)快速排序
- 流程:划分(Paitition) → 递归排序左右子区间;无需合并; 划分规则:选基准元素,左小右大。
- 复杂度分三种情况(必背)
- 最好情况:划分均衡(基准为中位数),递归式 ,;
- 最坏情况:划分极度不平衡(有序/逆序数组,基准为最值),递归式 ,;
- 平均情况:随机输入,;
- 优化方案
- 随机选择基准元素(RandomizedPartition),降低最坏情况概率;
- 提前判断数组是否已有序,跳过无效划分。
- 特点:原地排序、辅助空间小;不稳定排序。
(六)线性时间选择(求第k小元素)
问题:在无序数组中找第 小元素(包含最值、中位数)
-
随机选择版本
- 思路:借鉴快排划分,只递归处理目标所在单侧子区间;
- 平均复杂度:;最坏复杂度:。
-
最坏线性时间版本 [BFPTR算法]
基准选取规则:
- 数组按每5个元素分组;
- 每组取中位数;
- 递归求中位数的中位数作为划分基准;
- 保证划分后子区间长度不超过原长度的 ;
- 递归式:,最终复杂度 最坏 。
(七)平面最接近点对(分治经典应用题)
- 一维情况:数轴上找点对,分治+合并,复杂度 ;
- 二维平面情况(核心)
步骤:
- 按 x 坐标中位数分割平面为左右两部分;
- 递归求左右区域最小距离 ,令 ;
- 只检查分割线左右距离不超过 的点(候选点);
- 利用鸽巢原理:每个点最多只需对比 7 个点,合并步骤线性 ;
- 总递归式:,复杂度 。
常用递推式速解
- (归并、快排平均、最近点对)
- (二分搜索)
- (快排最坏、汉诺塔变形)
- (大整数乘法)
- (Strassen矩阵乘法)
Ch 3. 动态规划
动态规划 基础理论
1. 核心思想
动态规划(DP)用于多阶段最优化问题;将大问题拆分为子问题,记录子问题答案、避免重复计算,以空间换时间,把指数复杂度降为多项式复杂度。
对比分治:分治的子问题相互独立;动态规划的子问题大量重叠。
2. 两大必备性质
- 最优子结构:原问题的最优解,一定包含其子问题的最优解(DP前提)。
- 重叠子问题:递归过程中同一个子问题会被多次计算,DP通过表格存储结果,每个子问题只算一次。
3. 动态规划标准四步设计流程
- 分析最优解结构,验证最优子结构;
- 定义状态,递归写出最优值递推公式;
- 自底向上计算所有子问题最优值;
- 根据记录表回溯,构造完整最优解。
4. 两种实现方式
- 自底向上DP:常规写法,遍历填表,效率高、主流考点;
- 备忘录方法(自顶向下):递归+缓存,控制逻辑和纯递归一致,仅重复子问题查表,适合直观理解。
经典例题全解
(一)矩阵连乘问题
1. 问题描述
给定 个可连乘矩阵 ,矩阵乘法满足结合律,求最优加括号顺序,使得总的数乘次数最少。 设矩阵 维度:。
2. 状态定义
:矩阵子链 的最少数乘次数; :记录 的最优分割位置(用于回溯构造解)。
3. 递推公式
4. 复杂度
- 时间:(三层循环)
- 空间:(二维状态表)
5. 关键考点
- 穷举/分治解法是指数复杂度,DP优化为多项式复杂度;
- 根据 回溯输出最终加括号方案;
- 手算填表。
(二)最长公共子序列 LCS
1. 基本概念
子序列:元素顺序不变,但可不连续; 公共子序列:同时属于两个序列的子序列,求长度最长的一个。
2. 状态定义 :序列 与 的最长公共子序列长度; :记录状态转移方向,用于回溯构造LCS。
3. 递推公式
4. 复杂度与优化
- 基础版:时间 ,空间 ( 为两序列长度);
- 空间优化:仅保留两行数组,空间可降至 ;
- 可省略方向数组,直接由 表回溯。
(三)最大子段和
1. 问题描述
给定含正负整数的序列,求连续子数组的最大和;全负数时结果记为0。
2. 状态定义
:以第 个元素结尾的最大子段和。
3. 递推公式
最终答案:
4. 扩展考点
根据DP状态,回溯求出最大子数组的起止下标。
代码见 LeetCode
(四)0-1背包问题
1. 问题描述
件物品,每件重量 、价值 ,背包容量 ;每件物品最多选1件,求装入物品的最大总价值。
2. 状态定义
:从前 件物品中进行选择,且背包容量为 时的最大总价值。
(其中 ,)
3. 递推公式
边界条件:
- ,表示没有物品可选时,价值为 0。
- ,表示背包容量为 0 时,价值为 0。
4. 复杂度与特点
- 时间复杂度:,需要填充一个 的表格。
- 空间复杂度:基础实现为 ;可优化至 (使用一维数组 ,且内层循环必须逆序遍历 从 到 ,以防止物品被重复装入)。
- 算法特点:属于伪多项式时间算法。当背包容量 极大(如 )而物品总价值较小时,该算法效率会变差(此时可考虑转换状态定义,以“价值”为维度进行 DP)。
- 核心考点:二维表格的填表计算、一维数组的空间优化(及逆序原因)、通过状态表回溯选出具体装入的物品。
(五)流水作业调度(Johnson法则,偏理论+排序应用)
1. 问题描述
个作业依次经过两台机器 加工(先后), 为加工时间, 为加工时间,求作业顺序,使总完工时间最短。
2. 核心结论:Johnson不等式 & 调度规则
满足 的顺序为最优顺序,简化排序规则:
-
划分两组:
,;
-
按 升序排列;
-
按 降序排列;
-
最终顺序: 作业在前, 作业在后。
3. 复杂度
排序为主,时间 ,空间 。
Ch 4. 贪心算法
核心基础
1. 贪心算法思想
每一步只做当前局部最优选择,期望最终得到全局最优;选择一旦确定就不再回溯,执行方式为自顶向下、迭代缩减问题规模。
- 优势:逻辑简单、实现容易、效率高;
- 局限:并非所有问题都能得到全局最优,部分场景仅能求出近似解。
- 反例:特殊硬币找零,贪心选择结果差于全局最优。
2. 适用两大必备性质
- 最优子结构:原问题最优解包含子问题最优(贪心、动态规划共同前提)。
- 贪心选择性质:全局最优可通过一系列局部贪心选择逐步得到(贪心独有关键性质)。
3. 贪心通用框架
解集合S初始为空while 未得到完整可行解: 从候选集中选出局部最优元素x 满足约束则将x加入S 从候选集移除x返回S4. 贪心 vs 动态规划(高频对比题)
| 对比维度 | 贪心算法 | 动态规划 |
|---|---|---|
| 求解顺序 | 自顶向下,贪心选择+无回溯 | 自底向上,逐个求解子问题 |
| 子问题 | 无重叠,每步直接确定选择 | 存在大量重叠子问题,用空间缓存 |
| 选择方式 | 局部最优直接定,不做后续比较 | 枚举所有可能,择优选择 |
| 适用代表 | 活动安排、Dijkstra、最小生成树 | 0-1背包、LCS、矩阵连乘 |
关键区分:0-1背包不能用贪心,可分割的背包问题可以用贪心。
经典例题
(一)两类背包对比
-
0-1背包
物品不可分割,只能选/不选;无贪心选择性质,只能用动态规划。
-
可分割背包(分数背包)
物品可拆分;贪心策略:优先选择单位重量价值最大的物品。 算法复杂度:主要开销为排序,。
(二)活动安排问题
-
问题:选择最多互不冲突的活动(同一时间仅一个活动占用资源)。
-
最优贪心策略:按结束时间升序排序,每次选最早结束的活动。
原理:留出更多空闲时间,容纳后续活动。
-
复杂度:已排序 ;未排序需排序,。
-
最优性证明思路:
① 存在包含首个活动的最优解;② 选择后剩余子问题仍最优。
(三)最优装载问题
- 问题:轮船限重,装载最多集装箱。
- 贪心策略:优先装重量最轻的集装箱。
- 复杂度:排序 。
(四)Dijkstra 单源最短路径 [代码]
- 问题:带权非负有向图,求源点到所有顶点的最短路径。
- 贪心思路:维护已确定最短路径的顶点集合,每次从剩余顶点中选出当前路径最短的点加入,并更新路径长度。
- 复杂度(邻接矩阵实现):。
(五)哈夫曼编码(最优前缀码)[代码]
- 用途:数据压缩,构造最短平均码长的前缀编码。
- 核心规则:使用最小堆,反复合并两个频率最低的节点,生成哈夫曼树。
- 关键概念:前缀码(任一编码不是其他编码的前缀)、树总代价 。
- 复杂度:共次合并,堆操作。
(六)最小生成树(MST)
最小生成树(Minimum Spanning Tree, 简称 MST)是图论中的一个经典问题。它的核心目标是在一个带权重的无向连通图中,找到一棵包含所有顶点的树,使得这棵树的所有边的权重之和最小。
1. MST 性质
设是顶点子集,连接与的权值最小边,一定属于某一棵最小生成树(反证法证明)。
2. Prim 算法(基于点的贪心) [代码]
- 思路:从单个顶点出发,每次选取连接树内外权最小的边,逐步扩展生成树。
- 适用:稠密图;邻接矩阵实现 ,堆优化 。
3. Kruskal 算法(基于边的贪心) [代码]
- 思路:所有边按权升序,依次选边,用并查集判断是否构成环,无环则加入生成树。
- 适用:稀疏图;主要开销为边排序,。
(七)多机调度问题
- 问题:个不可中断作业分配到台机器,最小化总完工时间(NP完全问题)。
- 贪心近似策略:作业按处理时间降序,每次分配给当前负载最小的机器。
- 复杂度:排序 。
Ch 5. 回溯法
基础概念与核心对比
1. 回溯法定义
回溯法是基于深度优先搜索(DFS) 的系统化穷举算法,核心流程:尝试选择 → 递归深入 → 不满足约束则撤销选择(回溯); 本质 = 递归遍历 + 状态选择 + 状态撤销,依靠剪枝规避无效搜索,解决组合爆炸问题。
2. 与其他算法区分(选择/判断高频)
- 对比暴力搜索:回溯增加剪枝,提前终止无效路径,效率远高于纯暴力;
- 对比分治:分治子问题独立、无回溯;回溯子问题关联、需要恢复状态;
- 对比动态规划:DP存储子问题解避免重复计算;回溯不存子问题,靠剪枝优化。
3. 适用场景
主要解决约束满足问题、组合枚举、最优解搜索:
- 排列/组合/子集类问题;
- 棋盘问题(N皇后、数独);
- 路径、任务分配等带约束的决策问题。
核心术语(名词解释)
- 解空间:问题所有合法解的集合,一般表示为解向量 ,是所有决策的笛卡尔积。
- 解空间树:解的树形表达,根为初始状态,每层对应一步决策,叶子为完整解。
- 活结点:已生成、仍有未遍历子节点,可继续扩展。
- 死结点:所有子节点遍历完毕,无后续分支,必须回溯。
- 扩展结点:当前正在生成子节点的活结点。
回溯标准流程 & 通用模板
1. 四步执行流程
- 初始化:定义解空间、候选集、约束、路径容器、终止条件;
- 递归选择:遍历当前所有候选,选中一个并更新状态;
- 剪枝+终止判断:违反约束直接剪枝;到达叶子则记录有效解;
- 回溯撤销:移除当前选择、恢复状态,尝试下一个候选。
2. 通用伪代码模板
Backtrack(状态, 路径, 候选集){ if (到达终止条件) { 记录有效解; return; } for (遍历每一个候选选择) { if (违反约束) continue; // 剪枝 选择:加入路径、标记状态 Backtrack(新状态, 新路径, 候选集); // 递归 回溯:移除路径、恢复状态 }}四大剪枝策略(重中之重)
剪枝是回溯效率的核心,分为4类,可组合使用;设计原则:前置、精准、低开销。
-
可行性剪枝(约束剪枝)
当前路径已不满足问题硬性约束,直接截断分支。 例:N皇后同列/对角线冲突、背包超重。
-
最优性剪枝(限界剪枝)
针对求最优解问题:当前路径代价已差于已知最优解,后续不可能更优,直接剪枝。 例:旅行商、0-1背包求最大价值。
-
顺序剪枝
限制候选选择顺序,避免生成重复解。 例:组合、子集问题用
start参数保证下标递增,防止[2,3]和[3,2]重复。 -
数学剪枝
利用数学规律预判无效路径。 例:组合总和中,数组排序后,当前和+下一个元素已超过目标,后续更大元素直接跳过。
五、经典例题(原理+思路+复杂度+考点)
1. N皇后问题(可行性剪枝代表)
问题
棋盘放置个皇后,任意两个不同行、列、对角线。
约束判定
- 行:按行放置,天然满足;
- 列:标记已占用列;
- 主对角线(行-列 相等)、副对角线(行+列 相等)。
解向量
表示第行皇后所在列。
复杂度
- 无剪枝:;
- 剪枝后:远低于;
- 空间:(路径、标记数组、递归栈)。
2. 组合总和(顺序+数学剪枝结合)
问题
给定数组,元素可重复选,找出和为target的所有不重复组合。
核心优化
- 数组排序,为数学剪枝做铺垫;
start参数控制遍历起点(顺序剪枝,去重);- 当前和+候选值 > target 直接break(数学剪枝)。
复杂度
最坏 (为最大组合长度),剪枝后效率大幅提升;空间 。
3. 子集问题(顺序剪枝)
问题
求数组所有子集(含空集),子集不重复。
思路
用start保证选取下标严格递增,每进入一层递归就记录当前路径(无需等到叶子)。
复杂度
时间 (共个子集,每个子集处理);空间 。
4. 0-1背包(可行性+最优性剪枝)
问题
物品只能选/不选,背包限重,求最大价值及对应方案。
思路
- 每个物品二分支:选 / 不选;
- 可行性剪枝:选中后总重量超容量则截断;
- 最优性剪枝:当前价值+剩余物品理论最大价值 ≤ 已知最优,直接剪枝。
复杂度
无剪枝 ;剪枝后可处理中等规模数据;空间 。
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!
部分内容可能已过时