1.明显倒置问题——分治
1.1 描述算法思想
我们可以再归并排序的基础上来计算明显倒置。
- 分治:将一列数字平分为左右两列数字
- 治理:左右两列数字分别计算其明显倒置个数A、B
- 合并:计算左列右列(i在左列,j在右列)所含的明显倒置个数C,A+B+C即为明显倒置的总个数
1.2 写出算法伪代码
1 | def MS_OI(lists): #merge_sort_Obvious_inversion |
1.3 分析算法时间复杂度
时间复杂度与归并排序的相同,都为nlog(n)
2.工作最优安排问题——动态规划
2.1 描述算法思路
这道题和我们之前做的 阿里面试题之求括号数、求走楼梯的方法数类似,都是一个数组内的线性规划问题。
我们用一个数组OPT来表示这道题,数组值对应各天最优解,明显是满足最优子结构的。
- 首先计算0到2天的最优值,即两天之内的情况都工作不用休息
- OPT[0]=0、OPT[1]=w[1]、OPT[2]=w[1]+w[2]
- 我们从i=3->k来遍历计算这个数组,对于每个OPT[i],有三种情况:
- 1天前的最优值+1天休息:OPT[i]=OPT[i-1]
- 2天前的最优值+1天休息+1天工作:OPT[i]=OPT[i-2]+w[i]
- 3天前的最优值+1天休息+2天工作:OPT[i]=OPT[i-3]+w[i-1]+w[i]
2.2 OPT(k)递推式
1 | # OPT(0)=0 |
2.3 写出算法伪代码
1 | def work_arrange(w) |
2.4 分析算法时间复杂度
O(n),根据伪代码可知,我们的代码时间复杂度与n成正比。
直接证明法:推导递推式T(n)=T(n-1)+O(1)=T(n-2)+O(1)+O(1)=……=O(n)
数学归纳法证明:
- 当
n=0、1、2
时,算法时间复杂度为O(n)
- 设当
n=k
时,算法时间复杂度为O(k)=O(n)
。而当n=k+1
时,算法时间复杂度等于O(k)+O(1)=O(k+1)=O(n)
得证时间复杂度为O(n)
3.棋盘硬币收集问题——动态规划
3.1 描述算法思路
以下 列即x坐标
,行即y坐标
x+1往右,y+1往上
自顶向下遍历棋盘的行。
- 首先计算第n行的所有格子的总价值,因为是最高的棋子,所以总价值就是自身价值。
- 然后计算第n-1行的总价值,第n-1行的每个格子的总价值计算公式如下:
- 若是第1列:OPT(x,y)=max(OPT(x,y+1),OPT(x+1,y+1))+c(x,y)
- 若是第n列:OPT(x,y)=max(OPT(x,y+1),OPT(x-1,y+1))+c(x,y)
- 其余列:OPT(x,y)=max(OPT(x,y+1),OPT(x-1,y+1),OPT(x+1,y+1))+c(x,y)
- 同上,自顶向下遍历行计算,最终,得到全棋盘格子可收集最大硬币总价值。
⭐由于考虑到题目仅仅只计算底部任意一个格子的最大总价值,如下图:影响到OPT(x,y)的,仅仅是两条红色线以上的格子。所以我们可以在上述算法上做一点点修改,遍历行时可减少遍历格子数。可降低时间复杂度、提高计算效率。
⭐由于题目可在最顶部任意一排格子结束,对于这个要求,我们同样只要加个约束就好了。
3.2 OPT(x,y)递推式
- 若是第0列:OPT(x,y)=max(OPT(x,y+1),OPT(x+1,y+1))+c(x,y)
- 若是第n列:OPT(x,y)=max(OPT(x,y+1),OPT(x-1,y+1))+c(x,y)
- 其余列:OPT(x,y)=max(OPT(x,y+1),OPT(x-1,y+1),OPT(x+1,y+1))+c(x,y)
3.3 写出算法伪代码
以下下标,均是以python数组下标从零开始为前提。range(n)=[n-1,……,0]。
列=x=i
,行=y=j
1 | def CHESS_COIN(c): |
⭐为了使达到题目中的要求: 你可以选择在在最底部一排的任意格子开始
,在最顶部一排的任意格子结束
- 我们在遍历最顶部行时,做一个条件判断是否为最后一个格子(第M列)
1 | #这是上半部分初始化最高行的代码: |
- 我们在遍历行时要考虑函数是否在红线范围内,判断是否大于直线的值即可,
- 设最底行的格子坐标为(a,b)这里写个伪代码:
3.4 分析算法时间复杂度
⭐直接证明:
对于题目——棋盘硬币收集问题来说,想要获得一个最底部的格子的最大价值,最少必须要遍历其上方的格子数=
n^2
-(1/4)n^2
=(3/4)n^2
。即(3/4)n^2
<=f(n) <=n^2
。存在正的常数C=1和自然数n0=1,使得当n≥n0时, 有f(n)≤g(n)=n^2。
则称函数f (n) 在n 充分大时有上有界,且g(n) 是它的一个上界,记做f (n) = O(g(n))=O(n^2)
⭐数学归纳法证明:
- 当
n=1
时,算法时间复杂度为O(n^2)
- 设当
n=k
时,算法时间复杂度为O(k^2)=O(n^2)
。而当n=k+1
时,算法时间复杂度等于O((k+1)^2)=O(n^2)
得证时间复杂度为O(n^2)
3.5 证明不存在最差时间复杂度为小o(n^2)的动态规划算法
反证法:
假设存在一个动态规划算法的最差时间复杂度为
小o(n^2)
,即f(n)=o(g(n))
。即
0<=f(n)<=cg(n)
对于任意常量c>0
成立(n>=n0)。但是,对于题目——棋盘硬币收集问题来说,想要获得一个最底部的格子的最大价值,最少必须要遍历其上方的的格子数=
n^2
-(1/4)n^2
=(3/4)n^2
。假如此时取c取1/2
,则0<=f(n)<=(1/2)g(n)
不成立,矛盾。反证得不存在最差时间复杂度为
小o(n^2)
的动态规划算法,最优的算法时间复杂度只能是大O(n^2)
。
4.dijkstra算法流程图——贪心
5.kruskal\prim最小生成树——贪心
5.1 Kruskal
5.2 prim
6.环内活动安排问题——贪心
6.1 描述算法思想
该题,是一个环内的活动安排问题。我们可以遍历每个活动,将该活动从环中去除,余下的时间不成环,为普通活动安排问题。最后比较所有情况求得最优解。我们还可以用以下分类的方法,来减少一些计算量。
考虑以下两种情况下的安排,并且从这些安排中选出最优的。
- 最优的安排里没有过夜的活动,是一个0-24点的普通活动安排问题。
- 最优的安排里有过夜的活动,遍历过夜活动集每个过夜活动,剩下的也是普通活动安排问题。
⭐其实,对于过夜的活动,我们还可以用一些小的技巧来减少计算量。但因为计算包含关系有时复杂度会很高,这里当作一个变式。
- 若过夜活动两两不存在包含关系,则遍历计算,选择最优的安排。
- 对于活动A在活动B包含下的(即B开始早于A,结束晚于A,真子集关系),直接选择活动A。
6.2 分析算法时间复杂度
考虑以下两种情况下的安排,并且从这些安排中选出最优的。
首先以结束时间为基准,使用冒泡排序0am~24pm的活动。——O(nlogn)
遍历记下过夜的活动在排序数组中的位置,并且用一个数组将保存过夜活动——O(n)
最优的安排里没有过夜的活动,是一个0-24点的普通活动安排问题,得到
结果A
。——O(n)最优的安排里有过夜活动,遍历每个过夜活动,剩下的也是普通活动安排问题,寻找该过夜活动(如下)—O(n)
- tips:对于活动A在活动B包含下的(即B开始早于A,结束晚于A,真子集关系),直接选择活动A。若过夜活动两两不存在包含关系,则遍历计算值,选择最优的安排。但是此操作会增加时间复杂度,可以作为变式使用。
得到一个需要遍历的过夜活动集,遍历过夜活动集每个过夜活动。然后把它所占的区间从0-24小时中去除,然后从这个区间内使用普通活动安排方法计算,得到结果
B、C、D……
。——O(n^2)最后,对比几种情况
A、B、C……
选择最优值(最多活动)。——O(n)
综上,一般情况下,算法时间复杂度为O(n^2)。
6.3 证明算法正确性
(1)贪心选择性质:
对于不含跨夜活动的活动安排。是一个0~24小时普通活动的贪心选择:
证:假设,存在一个最优解A(不含跨夜活动情况下),且A中的活动也按结束时间非递减排序。A中的第一个活动是K。(设从零点开始的最早结束的活动为F)
如果K是F,那A就是从0点开始的贪心选择。
如果K不是F,那么设B=A-{K}∪{F},因为F早于K结束,且A中的活动是相容的。所以B中的活动也是相容的。又由于B中的活动个数与A中的活动个数相同,故A是最优的,即B是以F开始的最优活动安排。
所以,最优解A必包含F。
对于含跨夜活动的活动安排:
证:假设,含某跨夜活动X的最优解为A,且A中的活动也按结束时间非递减排序。A中的第一个活动是K。
(设F是X结束后开始的结束最早的活动安排)
如果K是F,那A就是去掉X所占区间后,从X结束时间开始的贪心选择。
如果K不是F,那么设B=A-{K}∪{F},因为F早于K结束,且A中的活动是相容的。所以B中的活动也是相容的。又由于B中的活动个数与A中的活动个数相同,故A是最优的,即B是以F开始的最优活动安排。
所以,最优解A(含某跨夜活动X),是去掉X后,从X结束时间开始的普通活动安排贪心选择。
对于两种类型的解,我们贪心选择活动数量最多的解。
(2)最优子结构性质:
- 对于不含跨夜活动的活动安排。是一个0~24小时普通活动的贪心选择:
- 反证法:假设A是活动集E最优解,A中第一个活动是K。设E去掉K后为E’,A去掉K之后为A’。
- 若E’中存在另一个解B‘ ,比A’有更多的活动,则将K加入B’中产生了另一个解B。这个B将比A拥有 更多的活动,与A的最优性矛盾。故最优解A去掉第一个活动K后,其子结构也是最优的。
- 对于含跨夜活动的活动安排,同上。
- 对于以上两种解,我们总是选择的全局最优解,包含了子结构的的最优解。