L7 - 算法优化与高效问题求解
L7 - 算法优化与高效问题求解
🎯 教学目标
- 掌握时间复杂度分析方法,能估算程序性能并优化算法
- 熟练应用前缀和技巧,解决区间统计类问题
- 深入理解二分法,实现查找与答案判定双重功能
- 构建递归思维模型,学会用记忆化搜索优化重复计算
📚 核心知识体系
一、时间复杂度分析(理论基石)
1 | // 示例:比较两种算法的耗时差异 |
复杂度对比表
数据规模 | O(n)(毫秒) | O(n²)(毫秒) |
---|---|---|
n=1e3 | 1 | 1000 |
n=1e4 | 10 | 100000 |
二、前缀和与差分数组(区间处理利器)
1. 一维前缀和模板
1 | vector<int> preSum(nums.size()+1, 0); |
2. 二维前缀和应用
1 | // 矩阵区域和计算 |
三、二分法双模式(查找与答案判定)
1. 经典二分查找
1 | int binarySearch(vector<int>& nums, int target) { |
2. 二分答案框架
1 | int findMaxValue(int maxLimit) { |
四、递归与记忆化搜索(性能飞跃)
1. 递归三要素实现
1 | int fibonacci(int n) { |
2. 记忆化搜索优化
1 | unordered_map<int, int> memo; |
性能对比
算法 | 计算fib(40)时间 | 时间复杂度 |
---|---|---|
普通递归 | >60秒 | O(2ⁿ) |
记忆化搜索 | <1毫秒 | O(n) |
🧩 综合应用案例
山脉数组查找目标值(融合二分与递归)
1 | int findInMountainArray(int target, MountainArray &mountainArr) { |
🏋️ 配套训练体系
1. 时间复杂度分析训练
题目1:基础复杂度判定
1 | // 请分析以下代码的时间复杂度 |
题目2:算法对比决策
假设计算机每秒处理1e6次操作,当n=1e5时:
- 算法A:时间复杂度O(n√n),需要预处理1秒
- 算法B:时间复杂度O(n²),无需预处理
应选择哪个算法?给出数学依据
2. 前缀和实战题单
题目1:子数组异或查询(LeetCode 1310)
» 给定数组,处理多个查询[i,j]
,返回从i到j的异或结果
» 关键技巧:利用异或前缀性质preXor[j+1] ^ preXor[i]
题目2:航班预订统计(LeetCode 1109)
» 处理n个航班的预订记录[first, last, seats]
,返回每日座位数
» 核心解法:差分数组+前缀和还原
题目3:最大子矩阵(LeetCode 面试题17.24)
» 给定二维矩阵,找出元素和最大的子矩阵
» 高阶技巧:二维前缀和压缩+一维最大子数组转化
3. 二分法专项训练
题目1:寻找峰值(LeetCode 162)
» 数组可能包含多个峰值,返回任意一个峰值的索引
» 思维突破:比较mid与mid+1决定搜索方向
题目2:H指数 II(LeetCode 275)
» 给定学者论文被引次数的升序数组,计算其H指数
» 判定条件设计:citations[mid] >= n - mid
题目3:分割数组的最大值(LeetCode 410)
» 将数组分割为m个连续子数组,最小化最大子数组和
» 答案二分法典型应用:验证给定最大值是否可行
4. 记忆化搜索挑战
题目1:带障碍的路径统计(LeetCode 63 改编)
» 网格中存在障碍物,求从左上角到右下角的路径数(允许→和↓移动)
» 进阶条件:若路径必须经过某特定点,如何修改记忆化策略
题目2:硬币组合问题(LeetCode 518 改编)
» 给定不同面额的硬币和总金额,求凑成金额的硬币组合数
» 空间优化:如何将二维记忆化压缩为一维DP
题目3:正则表达式匹配(LeetCode 10)
» 实现支持.
和*
的正则表达式匹配
» 记忆化技巧:用哈希表记录(i,j)位置的匹配结果
🧑💻 训练指导建议
- 复杂度分析:使用主定理处理递归式,对比不同阶的增长曲线图
- 前缀和题单:先手算推导矩阵区域和公式,再转化为代码实现
- 二分训练:所有题目先用闭区间写法实现,再改为左闭右开对比差异
- 记忆化搜索:先用树状图分析递归展开过程,再添加记忆化剪枝
📝 学习路径导图
graph LR A[时间复杂度] --> B[前缀和/差分] A --> C[二分法] B --> D[综合应用] C --> D D --> E[递归] E --> F[记忆化搜索] F --> G[动态规划基础]