第一章
1.算法的概念:算法是解决问题的一种方法或一个过程,算法是由若干条指令组成的有穷数列。
2.算法的四个性质:
① 输入:有零个或多个由外部提供的量作为算法的输入;
② 输出:算法产生至少一个量作为输出;
③ 确定性:组成算法的每条指令是清晰的,无歧义的;
④ 有限性:算法中每条指令的执行次数是有限的,执行每条指令的时间也是有限的。
程序是算法用某种程序设计语言的具体实现。可以不满足性质④
3. (1)大O表示算法的渐进上界,上界的阶越低,则评估越精确,结果就越有价值。
(2)欧米茄表示算法的渐进下界,这个下界的阶越高,则评估越精确,结果就越有价值。该渐进符号一般用于描述算法的最优复杂度
(3)θ用于界定函数的渐进上界和渐进下界。θ渐进符号是最严格的一个,因为它既描述了函数的上界,又描述了函数的下界。
4. (1)最坏时间复杂度:在最糟糕的情况下,执行这段代码的时间复杂度。比如在数组中查找不存在的变量x,需要将整个数组遍历一遍。
(2)最好时间复杂度:在最理想的情况下,执行这段代码的时间复杂度。比如要查找的变量x正好是数组的第一个元素。
(3)平均时间复杂度:指所有可能输入实例均以等概率出现的情况下,该算法的运行时间。
(4)一般情况下用最坏时间复杂度来讨论算法的时间复杂度,因为最坏情况下的时间复杂度是算法在任何输入实例上运行时间的界限,这样就保证了算法的运行时间不会比最坏情况更长。
第二章
1.直接或间接调用自身的算法称为递归算法。递归是指在在一个过程或函数的定义时出现调用本过程或本函数的成分
2. 若在函数中调用函数自身或者在过程的子部分中调用子部分自身的内容,称之为直接递归,又称自递归。
3. 若不同的函数和子过程之间互相调用,则称之为间接递归,任何间接递归都可以等价地转换为直接递归(自递归),所以我们讨论递归一般只讨论直接递归。
4.分治法的基本思想:将一个规模为n的问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相同。递归地接这些子问题,然后将各子问题的解合并得到原问题的解。
5.二分搜索:给定已排好序的n各元素a[0:n-1],现在要在这n各元素中找出一特定元素x。
二分搜索的基恩思想是将n个元素分成大致相同的两半,取a[n/2]与x进行比较。
6.归并排序:
7.快排:
8. (1)递归的基本思想:直接或间接地调用自身的算法。
(2)分治法的基本思想:将一个规模为n的问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相同。递归地解这些子问题,然后将各子问题的解合并得到原问题的解。
(3)贪心算法的基本思想:贪心算法首先设计某种贪心选择策略,第一步做出当前状态的最优选择;然后问题会被演化为与原问题相同但规模更小的子问题,最后用相同的贪心选择策略求解子问题。
(补充)贪心算法的基本要素包括贪心选择性质和最优子结构性质。
(3.1)贪心选择性质:指所求问题的整体最优解可以通过一系列局部最优解来达到。
(3.2)最优子结构性质:当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。
(4)回溯法的基本思想:
(4.1)针对所给问题,定义问题的解空间
(4.2)确定易于搜索的解空间结构
(4.3)以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。
(5)分支限界法的基本思想是什么:
(5.1)求解目标:分支限界法的求解目标是找出满足约束条件的最优解。
(5.2)搜索方式:分支限界法常以广度优先或以最小耗费、最大效益优先的方式搜索解空间树。
(5.3)在分支限界法中,每个活结点只有一次机会成为扩展结点。活结点一旦成为扩展结点,就一次性产生所有儿子结点。在这些儿子结点中,导致不可行或导致非最优解的儿子结点被舍弃,其余儿子结点被加入活结点表中。
(5.4)此后,从活结点表中取下一结点成为当前扩展结点,并重复上述结点扩展过程。这个过程一直持续到找到所需的解或活结点表为空时停止。
第三章
1.动态规划(DP)的基本要素:最优子结构性质,重叠子问题性质
2.动态规划算法的步骤:
找出最优解的性质,并刻画其结构特征
递归的定义最优值
以自底向上的方式计算最优值
根据计算最优值时得到的信息构造最优解
3.矩阵连乘
4.LCS
5.最大子段和
- 分治算法:O(nlogn)
- 动态规划算法:O(n)
6.01背包
第四章
1.贪心算法的基本要素:
贪心算法是什么:贪心算法通过一系列选择来得到问题的解,所做的每个选择都是当前状态下局部最好选择,即贪心选择。
基本要素:(1)贪心选择性质:所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。(2)最优子结构性质:当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质
2.贪心和DP的差异:与动态规划的区别:
贪心算法:
①贪心算法中,作出的每步贪心决策都无法改变,因为贪心策略是由上一步的最优解推导下一步的最优解,而上一步之前的最优解则不作保留。
②贪心算法每一步的最优解一定包含上一步的最优解。
动态规划算法:
①全局最优解中一定包含某个局部最优解,但不一定包含前一个局部最优解,因此需要记录之前的所有最优解
②动态规划的关键是状态转移方程,即如何由已求出的局部最优解来推导全局最优解
③边界条件:即最简单的,可以直接得出的局部最优解
3.活动排工
4.最优装载
5.哈夫曼编码
第五章
1.递归回溯
回溯法对解空间作深度优先搜索,因此,在一般情况下用递归方法实现回溯法。
void backtrack (int t){//t为递归深度,即当前扩展节点在解空间树中的深度;
if (t > n) //n用来控制递归深度
output(x);//算法已搜索至叶结点
else{
for (int i = f(n,t); i <= g(n,t); i++){//f(n,t)、g(n,t)分别表示在当前扩展节点处未搜索过的子树的起始编号和终止编号
x[t] = h(i);//h(i)表示在当前扩展结点处x[t]的第i个可选值
if (constraint(t) && bound(t))//constraint(t)和bound(t))分别是当前扩展结点处的约束函数和限界函数
//constraint(t)返回true表示在当前扩展结点处x[1:t]取值满足问题的约束条件,为false表示不满足约束条件,可剪去相应的子树。
//Bound返回true说明在x[1:t]取值未使目标函数越界,还可以继续由backtrack(t+1) 继续对其子树进一步搜索。Bound返回true ,说明已越界,可以剪去其子树
backtrack(t+1);
}
}
}
2.迭代回溯
采用树的非递归深度优先遍历算法,可将回溯法表示为一个非递归迭代过程。
void iterativeBacktrack (){
int t=1;
while (t > 0) {
if ( f(n,t) <= g(n,t))
for (int i = f(n,t); i <= g(n,t); i++) {
x[t] = h(i);
if (constraint(t) && bound(t)) {
if (solution(t))
output(x);
else t++;
}
}
else t--;
}
}
3.提高算法效率的关键
回溯法的算法框架:
针对所给问题,定义问题的解空间。解空间至少包含该问题的一个(最优)解;
确定易于搜索的解空间结构,通常组织为树(子集树、排列树等)或者图的形式;
以深度优先方式(递归搜索、迭代搜索等)搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。(剪枝函数的两种形式:①用约束函数在扩展结点处剪去不满足约束的子树;②用限界函数剪去得不到最优解的子树)
第六章
1. 回溯法和分支限界法通过解空间树来找问题的最优解,它们的相同和不同之处是什么、效率上有什么不同,算法效率的关键点是什么
不同之处:
1.求解目标不同:
回溯法的求解目标是找出解空间中满足约束条件的所有解,而分支限界法的求解目标是找出满足约束条件的一个解,或是在满足约束条件的解中找出使某一目标函数值达到极大或极小的解,即在某种意义下的最优解。
2.搜索方式不同:
回溯法以深度优先的方式搜索解空间,分支限界法则以广度优先或最小耗费优先的方式搜索解空间。
3.对扩展结点的扩展方式不同:
回溯法沿着当前扩展结点的子结点扩展下去。
分支限界法一次性产生当前扩展结点的所有儿子结点。
4.存储空间的要求不同:
分支限界法的存储空间比回溯法大得多,因此当内存容量有限时,回溯法成功的可能性更大。
算法效率的关键点:
在搜索时,绝大部分需要用到剪枝,剪枝策略就是寻找过滤条件,提前减少不必要的搜索路径。
2.队列
3.优先队列