《软件设计师》复习笔记(10.1)——算法特性、时间复杂度、递归、分治、动态规划
目录
一、算法的五大特性
二、算法复杂度分析
1. 时间复杂度
2. 常见复杂度示例
三、递归算法
1. 核心要素
2. 时间复杂度分析
真题示例:
算法A时间复杂度求解
算法B与算法A比较
四、分治法
1. 核心思想
2. 典型应用
五、动态规划法(Dynamic Programming, DP)
1. 核心思想
2. 实现步骤
3. 经典问题:0-1背包问题
一、算法的五大特性
- 有穷性:算法必须在有限步骤内终止,每步执行时间有限。
- 确定性:指令无歧义,相同输入必得相同输出。
- 可行性:操作可通过基本运算(如加减乘除)有限次实现。
- 输入:允许零或多个输入,取自特定集合。
- 输出:至少一个输出,与输入存在逻辑关联。
二、算法复杂度分析
1. 时间复杂度
- 定义:用函数 T(n) 表示输入规模 n 与基本操作数的关系。
- 三种情况:
- 最佳情况(最少操作,如查找元素在首位)。
- 最坏情况(最多操作,如元素不在数组中)。
- 平均情况(期望操作数)。
- 渐进符号:
- O(n):上界(最坏情况)。
- Ω(n):下界(最佳情况)。
- Θ(n):紧确界(精确复杂度)。
2. 常见复杂度示例
复杂度 | 示例代码场景 |
---|---|
O(1) | 高斯求和公式 sum = (1+n)*n/2 |
O(n) | 单层循环遍历数组 |
O(n2) | 嵌套循环(如冒泡排序) |
O(logn) | 循环中变量指数增长(如 count *= 2 ) |
三、递归算法
1. 核心要素
- 递归出口:终止条件(如阶乘中
n=0
返回1)。 - 递归体:问题分解为更小同类问题(如
n * Factorial(n-1)
)。
2. 时间复杂度分析
- 展开法:将递归式展开为求和式。
示例:
真题示例:
已知算法A的运行时间函数为T(n)=8T(n/2)+n^2,其中n表示问题的规模,则该算法的时间复杂度为(62 )。另已知算法B的运行时间函数为T(n)=XT(n/4)+n^2,其中n表示问题的规模。对充分大的n,若要算法B比算法A快,则X的最大值为( )。
(62)A. Θ(n) B. Θ(nlgn) C. Θ(n^2)
D. Θ(n^3) A. 15 B. 17 C. 63 D. 65
算法A时间复杂度求解
对于算法A,其运行时间函数为 ,这里可以使用主定理(Master - Theorem)来求解时间复杂度。 主定理的一般形式为:对于
(a≥1,b>1),比较 f(n) 与
的关系来确定时间复杂度。
- 在 T(n)=8T(2n)+n2 中,a=8,b=2,则
,
。
- 因为
(ϵ>0 ,这里 ϵ=1 ,
),所以 T(n)=Θ(n3) 。
算法B与算法A比较
对于算法B,其运行时间函数为 ,同样使用主定理,这里 a=X ,b=4 ,则
,
。 要使算法B比算法A快,即算法B的时间复杂度要小于算法A的时间复杂度 Θ(n3) 。 根据主定理,当
时,
,为了使 T(n)<Θ(n3) ,则需要
。 根据对数的性质,将其转化为指数形式,
,即 X<64 ,所以 X 的最大值为 63 。
解析:T(n)公式中本就有n²,而且还是一个递推公式,递归公式中也有n/2,可知实际有n³个数量级;算法B比A快,可令XT(n/4)+n²<8T(n/2)+n²,推导出X<8T(n/2)/T(n/4),将括号内分母取出,因为是n³级别,取出后上述公式可转化为X<8*(1/2)³T(n)/(1/4)³T(n),进一步简化消除可得X<1/(1/64),即X<64,X最大值为63。
四、分治法
1. 核心思想
- 三步流程:
- 分解:将问题划分为独立子问题(如归并排序中将数组二分)。
- 求解:递归解决子问题(子数组排序)。
- 合并:合并子问题的解(合并有序子数组)。
2. 典型应用
- 归并排序、快速排序、二分查找。
五、动态规划法(Dynamic Programming, DP)
1. 核心思想
- 与分治法的区别:
- 分治法:子问题独立,无重叠,递归求解(如归并排序)。
- 动态规划:子问题存在重叠,需存储中间结果(填表法)避免重复计算。
- 适用条件:
- 最优子结构:全局最优解包含局部最优解(如背包问题的最优解由子问题最优解构成)。
- 重叠子问题:子问题被多次重复计算(如斐波那契数列)。
2. 实现步骤
- 定义最优解的结构:明确问题如何分解为子问题(如背包问题的物品选择策略)。
- 递归或迭代计算最优值:
- 自顶向下:带备忘录的递归(记忆化搜索)。
- 自底向上:填表法(如二维数组递推)。
- 构造最优解:根据计算结果回溯路径(如背包问题中哪些物品被选中)。
3. 经典问题:0-1背包问题
有n个物品,第i个物品价值为vi,重量为wi,其中vi和wi均为非负数,背包的容量为W,W为非负数。现需要考虑如何选择装入背包的物品,使装入背包的物品总价值最大。
满足约束条件的任一集合(x1, x2, …, xn)是问题的一个可行解,问题的目标是要求问题的一个最优解。考虑一个实例,假设n = 5,W = 17,每个物品的价值和重量如表所示,可将物品1、2和5装入背包,背包未满,获得价值22,此时问题解为(1, 1, 0, 0, 1);也可以将物品4和5装入背包,背包装满,获得价值24,此时解为(0, 0, 0, 1, 1)。
>物品编号 >1 >2 >3 >4 >5 价值v 4 5 10 11 13 重量w 3 4 7 8 9
(1) 刻画0 - 1背包问题的最优解的结构。 可以将背包问题的求解过程看作是进行一系列的决策过程,即决定哪些物品应该放入背包,哪些物品不放入背包。如果一个问题的最优解包含了物品n,即xn = 1,那么其余x1,x2,…,xn - 1一定构成子问题1, 2, …, n - 1在容量为W - wn时的最优解。如果这个最优解不包含物品n,即xn = 0,那么其余x1,x2,…,xn - 1一定构成子问题1, 2, …, n - 1在容量为W时的最优解。
(2) 递归定义最优解的值。 根据上述分析的最优解的结构递归地定义问题最优解。设c[i, w]表示背包容量为w时i个物品导致的最优解的总价值,得到下式。显然,问题要求c[n, W]。
基本情况(Base Case):
- 当物品数量 i=0(没有物品可选)或背包容量 w=0(无法装任何物品)时,最大价值
当前物品太重,无法装入背包:
- 如果当前物品 i 的重量 wi>w(超过剩余容量),则不能选它,最优解等于前 i−1 个物品在容量 w 下的最优解:
![]()
当前物品可以装入背包:
- 如果 wi≤w,则需要决策是否选择物品 i:
- 选:价值增加 vi,剩余容量减少 wi,即
- 不选:保持前 i−1 个物品的解,即
- 取两者中的最大值: