个人用高级算法与分析笔记(待补充)

一、算法分析方法

时间复杂度

下界复杂度/最低复杂度: Ω ( f ( x ) ) \Omega(f(x)) Ω(f(x))
上界复杂度/最高复杂度 O ( f ( x ) ) O(f(x)) O(f(x))
非紧渐近上界 o ( f ( x ) ) o(f(x)) o(f(x))
非紧渐近下界 ω ( f ( x ) ) ω(f(x)) ω(f(x))
上下确界 Θ ( f ( x ) ) \Theta(f(x)) Θ(f(x))
在这里插入图片描述
等价 R \mathcal{R} R f R g f\mathcal{R}g fRg等价于 f ( n ) = Θ ( g ( n ) ) f(n)=\Theta(g(n)) f(n)=Θ(g(n))
前序 ≺ \prec f ≺ g f\prec g fg等价于 f ( n ) = o ( g ( n ) ) f(n)=o(g(n)) f(n)=o(g(n))
1 ≺ l o g l o g n ≺ l o g n ≺ n ≺ n 3 4 ≺ n ≺ n l o g n ≺ n 2 ≺ 2 n ≺ n ! ≺ 2 n 2 1\prec log logn \prec logn\prec\sqrt{n}\prec n^{\frac{3}{4}} \prec n \prec nlogn \prec n^2 \prec 2^n \prec n! \prec 2^{n^2} 1loglognlognn n43nnlognn22nn!2n2

空间复杂度(需要排除输入的空间开销!)

事实上,空间复杂度不是考虑的首选,因为空间复杂度的上界不会超过时间复杂度!

最优算法:时间复杂度在 Ω ( f ( x ) ) \Omega(f(x)) Ω(f(x)) O ( f ( x ) ) O(f(x)) O(f(x))之间
eg1:对于朴素的二分查找,最好情况是 Ω ( 1 ) \Omega(1) Ω(1),最坏情况是 O ( l o g n ) O(logn) O(logn),平均复杂度是 O ( l o g n ) O(logn) O(logn),空间复杂度是 O ( 1 ) O(1) O(1)
eg2:对于朴素的冒泡排序,最好情况,最坏情况,平均情况为 Θ ( n 2 ) \Theta(n^2) Θ(n2),空间复杂度为 O ( 1 ) O(1) O(1)
eg3:对于朴素的归并排序,最好情况,最坏情况,平均情况为 Θ ( n l o g n ) \Theta(nlogn) Θ(nlogn),空间复杂度为 O ( n ) O(n) O(n)
eg4:对于朴素的快速排序,最好情况为 Ω ( n l o g n ) \Omega(nlogn) Ω(nlogn),最坏情况为 O ( n 2 ) O(n^2) O(n2),平均情况为 O ( n l o g n ) O(nlogn) O(nlogn),空间复杂度为 O ( l o g n ) O(logn) O(logn)
在这里插入图片描述

二、分治问题

递归复杂度计算

对于递归复杂度 T ( n ) = a T ( ⌈ n / b ⌉ ) + O ( n d ) , a > 0 , b > 1 , d ≥ 0 T(n)=aT(\lceil n/b\rceil)+O(n^d),a>0,b>1,d\geq0 T(n)=aT(⌈n/b⌉)+O(nd),a>0,b>1,d0,有
T ( n ) = { O ( n d ) i f   d > l o g b a O ( n d l o g n ) i f   d = l o g b a O ( n l o g b a ) i f   d < l o g b a T(n)=\left\{\begin{array}{ll}O(n^d) & if\ d>log_ba \\ O(n^dlogn) & if\ d=log_ba \\ O(n^{log_ba}) & if\ d<log_ba\end{array}\right. T(n)= O(nd)O(ndlogn)O(nlogba)if d>logbaif d=logbaif d<logba

二分搜索

mid是向下取整!
T ( n ) = T ( n / 2 ) + O ( 1 ) T(n)=T(n/2)+O(1) T(n)=T(n/2)+O(1),即 a = 1 , b = 2 , d = 0 a=1,b=2,d=0 a=1,b=2,d=0,则复杂度为 O ( l o g n ) O(logn) O(logn)
在这里插入图片描述

归并排序

T ( n ) = 2 T ( n / 2 ) + O ( n ) T(n)=2T(n/2)+O(n) T(n)=2T(n/2)+O(n),即 a = 2 , b = 2 , d = 1 a=2,b=2,d=1 a=2,b=2,d=1,复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)
在这里插入图片描述
在这里插入图片描述

Volker Strassen矩阵乘法

对于矩阵 X = [ A B C D ] , Y = [ E F G H ] X=\left[\begin{array}{cc}A&B \\ C&D\end{array}\right],Y=\left[\begin{array}{cc}E&F \\ G&H\end{array}\right] X=[ACBD],Y=[EGFH],则
X Y = [ A B C D ] [ E F G H ] = [ A E + B G A F + B H C E + D G C F + D H ] XY=\left[\begin{array}{cc}A&B \\ C&D\end{array}\right]\left[\begin{array}{cc}E&F \\ G&H\end{array}\right]=\left[\begin{array}{cc}AE+BG&AF+BH \\ CE+DG&CF+DH\end{array}\right] XY=[ACBD][EGFH]=[AE+BGCE+DGAF+BHCF+DH]
因此对于一个size为 n n n X Y XY XY,分割为了 8 8 8个size为 n / 2 n/2 n/2的矩阵后做加法(加法的复杂度是 O ( n 2 ) O(n^2) O(n2),要矩阵内每个元素两两相加),如此递归。
T ( n ) = 8 T ( n / 2 ) + O ( n 2 ) T(n)=8T(n/2)+O(n^2) T(n)=8T(n/2)+O(n2),即 a = 8 , b = 2 , d = 2 a=8,b=2,d=2 a=8,b=2,d=2,则时间复杂度为 O ( n 3 ) O(n^3) O(n3),这也是常规矩阵乘法的复杂度
而Volker Strassen矩阵乘法,多了一个trick:

在这里插入图片描述
这样就只需要计算 7 7 7个子矩阵,即 T ( n ) = 7 T ( n / 2 ) + O ( n 2 ) T(n)=7T(n/2)+O(n^2) T(n)=7T(n/2)+O(n2),即 a = 7 , b = 2 , d = 2 a=7,b=2,d=2 a=7,b=2,d=2,则时间复杂度为 O ( n l o g 2 7 ) ≈ O ( n 2.81 ) O(n^{log_27})\approx O(n^{2.81}) O(nlog27)O(n2.81)

三、贪心算法

在这里插入图片描述
对于一维数轴上若干条直线,最多可以兼容多少条线段互不重合?
先根据长度进行升序排序,然后依次放入不重合的,可以得到答案为 { B , E , H } \{B,E,H\} {B,E,H}
在这里插入图片描述
对于若干个进程,有工作时间 t i t_i ti与到达时间 d i d_i di,如何安排顺序让进程的总等待时间最少?(非抢占)
先根据到达时间升序排序,相同到达时间的根据工作时间安排先后。

在这里插入图片描述

四、动态规划DP

01背包为例,给定 n n n个物品与容量为 W W W的背包,每个物品有体积 w i > 0 w_i>0 wi>0和价值 v i > 0 v_i>0 vi>0,求背包能装满的最大的价值。

在这里插入图片描述
在01背包问题中贪心算法并非最优!
(如果以 v i / w i v_i/w_i vi/wi的比例为例来降序选择的话,选择 1 , 2 , 5 1,2,5 1,2,5号三件则是 35 35 35的value,但是选择 3 , 4 3,4 3,4号两件则是 40 40 40。)
d p [ i ] [ j ] dp[i][j] dp[i][j]表示在 1 ∼ i 1\sim i 1i的物品中选择,且最大价值不超过 j j j的最大价值。
d p [ i ] [ j ] = m a x { d p [ i − 1 ] [ j ] , v [ i ] + d p [ i − 1 ] [ j − w [ i ] ] } dp[i][j]=max\{dp[i-1][j],v[i]+dp[i-1][j-w[i]]\} dp[i][j]=max{dp[i1][j],v[i]+dp[i1][jw[i]]}(分别表示选第 i i i个和不选的情况,如果 w [ i ] > j w[i]>j w[i]>j,则不考虑后半个部分,即 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i1][j]
对于边界情况 j = 0 j=0 j=0,则 d p [ i ] [ j ] = 0 dp[i][j]=0 dp[i][j]=0
时间复杂度为 O ( n W ) O(nW) O(nW)

五、图论

握手定理:所有端点的入度与出度之和为边数量的两倍 ∑ v ∈ V d ( v ) = 2 ∣ E ∣ \sum_{v\in V}d(v)=2|E| vVd(v)=2∣E
完全图 K n K_n Kn
二分图 K m , n K_{m,n} Km,n
星图 K 1 , n K_{1,n} K1,n二分图的特殊情况
r分割图 K r ( m ) K_{r(m)} Kr(m)

最短路径

Dijkstra算法(单源最短路径,不可用于负权边)

d [ v ] = m i n ( d [ v ] , d [ u ] + w u , v ) d[v]=min(d[v],d[u]+w_{u,v}) d[v]=min(d[v],d[u]+wu,v)松弛操作
在这里插入图片描述

Bellman-Ford算法(单源最短路径,可用于负权边)

在Dijkstra算法的松弛操作基础上,最多 n − 1 n-1 n1次松弛就可以跑完全部的可能,但如果出现了负环的话,则说明 n − 1 n-1 n1次松弛之后仍然有可以松弛的边。
(判断是否有负环:建立一个超级源点,与所有点连接一个权值为 0 0 0的边,并以这个源点运行算法。)
在这里插入图片描述

floyd算法(全源最短路径,可以有负权边不能有负环)

时间复杂度 O ( n 3 ) O(n^3) O(n3)
在这里插入图片描述

Johnson算法(全源最短路径,可以有负权边不能有负环)

时间复杂度 O ( m n l o g m ) O(mnlogm) O(mnlogm)
1.建立一个超级源点,与所有点连接一个权值为 0 0 0的边。从超级源点跑一次Bellman-Ford求出到其他点的最短路。得到图中所有点 p p p的势能为最短路路径长度 h p h_p hp
2.对图中任意一条边 u → v u\rightarrow v uv且权值为 w w w。将该边权值定义为 w + h u − h v w+h_u-h_v w+huhv(类似重力势能的结构)
3.以每个点为起点,各自进行Dijkstra算法

矩阵快速幂

在这里插入图片描述

网络流(有源点与汇点的图)

容量 f ( u , v ) f(u,v) f(u,v):一条边上可供流过的最大流量
流量 c ( u , v ) c(u,v) c(u,v):一条边上流过的实际流量( f ( u , v ) ≤ c ( u , v ) f(u,v)\leq c(u,v) f(u,v)c(u,v)
残量 w ( u , v ) w(u,v) w(u,v):一条边上的容量-流量,剩下可流的最大流( w ( u , v ) = c ( u , v ) − f ( u , v ) w(u,v)=c(u,v)-f(u,v) w(u,v)=c(u,v)f(u,v)
除了源点与汇点,每个点的流入总量=流出总量
f ( u , v ) = − f ( v , u ) f(u,v)=-f(v,u) f(u,v)=f(v,u)反对称性
增广路:一条从源点到汇点的路径,路径上每一条边的残量 w ( u , v ) > 0 w(u,v)>0 w(u,v)>0
最大流等于最小割!(最小割:为了使
源点与汇点不连通**,至少要去掉多少条边)

ford–fulkerson增广(求最大流)

0.令不存在边的权值为 0 0 0。(视为一条流量为 0 0 0的边)
1.找到一条增广路,找到这条路上最小的 w ( u , v ) w(u,v) w(u,v)记为 f l o w flow flow
2.在这条增广路上的每一条边 ( u , v ) (u,v) (u,v)上减去 f l o w flow flow
3.在 ( v , u ) (v,u) (v,u)上加上 f l o w flow flow(建立反向边,之后走反向边就意味着回溯)
4.重复以上,直到找不到增广路为止,此时之前所有操作过的 f l o w flow flow之和就是最大流。

时间复杂度为 O ( ∣ E ∣ ∣ f ∣ ) O(|E||f|) O(E∣∣f) E E E是边数, f f f是最大流大小。)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值