翻到了上学期整理的一些算法设计与分析的算法,考之前扫几眼还是有点用的hh
第一章主要是介绍算法的定义巴拉巴拉就跳过啦
第二章:递归与分治
1. 递归算法
| 算法/问题 | 核心思想 | 关键公式/步骤 | 时间复杂度 | 经典例题 |
|---|---|---|---|---|
| 阶乘 | 分解为n×(n-1)! | fact(n)=n*fact(n-1),初始fact(1)=1 | O(n) | 计算5! |
| 斐波那契 | 分解为F(n-1)+F(n-2) | F(n)=F(n-1)+F(n-2),初始F(0)=0,F(1)=1 | O(2ⁿ) | 求F(10) |
| 汉诺塔 | 分三步移动n个盘 | T(n)=2T(n-1)+1,初始T(1)=1 | O(2ⁿ) | 移动3个盘的最小步骤 |
| 全排列 | 交换+递归剩余元素 | 回溯法:固定首位,递归生成剩余排列 | O(n!) | 生成[1,2,3]的全排列 |
| 整数划分 | 按是否包含m划分 | P(n,m)=P(n-m,m)+P(n,m-1) | O(2ⁿ) | 将5划分为正整数之和 |
2. 分治算法
| 算法 | 分治策略 | 主定理应用 | 时间复杂度 | 关键步骤 |
|---|---|---|---|---|
| 二分搜索 | 每次比较中间元素 | T(n)=T(n/2)+O(1) → 情况2 | O(logn) | 有序数组查找target |
| 大整数乘法 | 分块计算+合并 | T(n)=3T(n/2)+O(n) → 情况1 | O(n^1.59) | 计算1234×5678(分治优化) |
| 合并排序 | 分半排序+合并 | T(n)=2T(n/2)+O(n) → 情况2 | O(nlogn) | 对[5,2,4,7]排序 |
| 快速排序 | 划分+递归左右子数组 | 最坏O(n²)(已排序),平均O(nlogn) | O(nlogn) | 选择枢轴(随机化避免最坏情况) |
| 最近点对 | 分治+中间带扫描 | T(n)=2T(n/2)+O(n) → 情况2 | O(nlogn) | 二维平面找最近两点(鸽巢原理证7个点) |
第三章:动态规划(DP)
1. 通用解题框架
- 定义状态:明确
dp[i][j]的含义(如dp[i][j]表示子串i到j的最优解) - 状态转移:根据子问题关系列方程(如
dp[i][j] = min(dp[i][k]+dp[k+1][j]+cost)) - 初始化:边界条件(如
dp[i][i]=0) - 填表顺序:通常自底向上(如按子问题规模从小到大)
- 追踪解:逆向回溯决策路径(如背包问题逆推物品选择)
2. 经典DP问题详解
| 问题 | 状态定义 | 状态转移方程 | 填表示例 | 时间复杂度 |
|---|---|---|---|---|
| 矩阵连乘 | m[i][j]:矩阵i到j的最小乘法次数 | m[i][j]=min{m[i][k]+m[k+1][j]+p[i-1]p[k]p[j]} | 下三角矩阵逐行填 | O(n³) |
| LCS | dp[i][j]:X[0..i]和Y[0..j]的最长公共子序列长度 | dp[i][j] = dp[i-1][j-1]+1(若X[i]=Y[j])else max(dp[i-1][j], dp[i][j-1]) | 二维表从左到右填 | O(mn) |
| 最大子段和 | dp[i]:以i结尾的最大子段和 | dp[i]=max(nums[i], dp[i-1]+nums[i]) | 一维数组线性扫描 | O(n) |
| 0/1背包 | dp[i][w]:前i件物品容量w的最大价值 | dp[i][w]=max(dp[i-1][w], dp[i-1][w-wt[i]]+val[i]) | 二维表从左上到右下填 | O(nW) |
| 最优二叉搜索树 | dp[i][j]:关键字i到j的最小搜索代价 | dp[i][j]=min{dp[i][k-1]+dp[k+1][j]}+sum(p[i..j]) | 对角线填充 | O(n³) |
3. DP优化技巧
- 滚动数组:空间优化(如背包问题用一维数组)
- 备忘录法:记忆化搜索(如斐波那契数列缓存中间结果)
- 四边形不等式:优化矩阵连乘的k取值范围
第四章:贪心算法
1. 贪心选择性质证明方法
- 交换论证:假设存在更优解,通过交换元素导出矛盾
- 归纳法:证明每步选择不破坏全局最优性
- 拟阵理论:子集系统的遗传性和交换性
2. 典型贪心算法
| 问题 | 贪心策略 | 算法步骤 | 时间复杂度 | 正确性证明关键 |
|---|---|---|---|---|
| 活动安排 | 按结束时间升序选择相容活动 | 1. 排序活动 2. 选择最早结束且不冲突的活动 | O(nlogn) | 反证法:若存在更优解可交换调整 |
| 分数背包 | 按价值/重量比降序装填 | 1. 计算性价比 2. 尽可能多装最高性价比物品 | O(nlogn) | 显然最优 |
| 哈夫曼编码 | 合并频率最低的节点 | 1. 建最小堆 2. 每次取两最小节点合并 | O(nlogn) | 最优前缀码性质(左0右1) |
| Dijkstra算法 | 每次选择未处理的最近节点松弛邻边 | 1. 初始化dist数组 2. 优先队列选择最小dist节点 3. 松弛操作 | O(E+VlogV) | 归纳法证每次选择最短路径 |
| Prim算法 | 从任意点出发扩展最小边 | 1. 维护候选边集 2. 每次选连接树的最小边 | O(E+VlogV) | 割性质(最小边必在MST中) |
| Kruskal算法 | 按边权升序选择不形成环的边 | 1. 排序所有边 2. 用并查集避免环 | O(ElogE) | 归纳法证每次选择安全边 |
3. 贪心 vs DP对比
| 特性 | 贪心算法 | 动态规划 |
|---|---|---|
| 适用条件 | 局部最优=全局最优 | 最优子结构+重叠子问题 |
| 计算效率 | 通常更高(O(nlogn)) | 通常较高(O(n²)或O(n³)) |
| 典型问题 | 活动安排、哈夫曼编码 | 背包问题、LCS |
| 解的正确性 | 需严格证明 | 由状态转移保证 |
高频考点速查表
-
必考推导
- 主定理应用(如归并排序的复杂度推导)
- 背包问题的填表(如给定物品和容量,求最大价值)
-
必背伪代码(不全,重点是理解)
# 快速排序分区(Partition) def partition(arr, low, high): pivot = arr[high] i = low - 1 for j in range(low, high): if arr[j] <= pivot: i += 1 arr[i], arr[j] = arr[j], arr[i] arr[i+1], arr[high] = arr[high], arr[i+1] return i+1 -
易错点
- 分治法的递归终止条件遗漏(如二分搜索low>high时终止)
- DP问题忘记初始化(如LCS中空串对应dp[0][j]=0)
- 贪心算法未排序直接选择(如活动安排需先按结束时间排序)
建议:
- 手写每个算法的伪代码(如Dijkstra的优先队列实现)
- 完成至少3道完整DP填表题(如矩阵连乘、LCS)
- 对比记忆分治/DP/贪心的经典问题差异(如最大子段和的三种解法)
1636

被折叠的 条评论
为什么被折叠?



