高等算法课程笔记Lecture 1

作者的博客:
CSDN: https://blog.csdn.net/u013031229
博客园: https://www.cnblogs.com/fzyz999/
主站:https://www.pig2earth.top/

课程主要内容

随机算法:如何分析随机算法的成功率

近似算法:近似算法的设计技巧

Big O Notation

一般用大O来衡量算法复杂度。

f ( n ) = O ( g ( n ) ) 代表 ⩽ f(n) = O(g(n)) \text{代表} \leqslant f(n)=O(g(n))代表

f ( n ) = Ω ( g ( n ) ) 代表 ⩾ f(n)=\Omega(g(n)) \text{代表} \geqslant f(n)=Ω(g(n))代表

证明 f ( n ) = Θ ( g ( n ) ) f(n)=\Theta(g(n)) f(n)=Θ(g(n)),等价于证明 f ( n ) ≥ ( g ( n ) ) f(n)\geq(g(n)) f(n)(g(n)) f ( n ) ≤ c ⋅ g ( n ) f(n)\leq c\cdot g(n) f(n)cg(n)

排序问题

待排序集合S包含n个数,对其进行排序。

解决排序的思路:

  1. 找到集合S中的中位数y
  2. 将S划分为小于y和大于y的两部分 S 1 , S 2 S_1,S_2 S1,S2
  3. 递归对 S 1 S_1 S1 S 2 S_2 S2排序

计算复杂性:

  1. 找到集合S中的中位数y(cn)
  2. 将S划分为小于y和大于y的两部分 S 1 , S 2 S_1,S_2 S1,S2(n)
  3. 递归对 S 1 S_1 S1 S 2 S_2 S2排序
    可以得到复杂性为: T ( n ) < = 2 T ( n / 2 ) + ( c + 1 ) n T(n) <= 2T(n/2) + (c+1)n T(n)<=2T(n/2)+(c+1)n

为什么快排没有这么做?

  1. 找中位数算法的时间复杂度cn中的c比较大,以前大约是20以上,现在可以优化到2左右
  2. 找中位数的算法编程上较为复杂

假如我们可以以更低的代价求出大小相近的 S 1 S_1 S1 S 2 S_2 S2?很难做到,难度和直接找中位数差不多。

快排的思路:

  1. 寻找集合S中随机的一个数y (O(1))
  2. 将S划分为小于y和大于y的两部分 S 1 , S 2 S_1,S_2 S1,S2(n)
  3. 递归对 S 1 S_1 S1 S 2 S_2 S2排序

快排平均复杂度求解思路:y是第k大的概率是一样的(k可能为1…n)据此可以列出递推式:
T ( n ) = ∑ k = 1 n 1 n ( T ( k − 1 ) + T ( n − k ) + n − 1 ) T(n) = \sum_{k=1}^{n} \frac{1}{n}(T(k-1)+T(n-k)+n-1) T(n)=k=1nn1(T(k1)+T(nk)+n1)
所以
T ( n ) = 2 n ( T ( 0 ) + T ( 1 ) + ⋯ + T ( n − 1 ) ) + n − 1 T(n)=\frac{2}{n}(T(0)+T(1)+\cdots+T(n-1))+n-1 T(n)=n2(T(0)+T(1)++T(n1))+n1

这个递推式可以想办法消掉和n、n-1无关的项。首先对上式做一下变幻:
n T ( n ) = 2 ( T ( 0 ) + T ( 1 ) + ⋯ + T ( n − 1 ) ) + n ( n − 1 ) nT(n)=2(T(0)+T(1)+\cdots+T(n-1))+n(n-1) nT(n)=2(T(0)+T(1)++T(n1))+n(n1)

然后,通过相减消掉后面的项:
n T ( n ) − ( n − 1 ) T ( n − 1 ) = 2 T ( n − 1 ) + n ( n − 1 ) − ( n − 1 ) ( n − 2 ) nT(n)-(n-1)T(n-1)=2T(n-1)+n(n-1)-(n-1)(n-2) nT(n)(n1)T(n1)=2T(n1)+n(n1)(n1)(n2)

整理后得到
n T ( n ) = ( n + 1 ) T ( n − 1 ) + 2 ( n − 1 ) nT(n)=(n+1)T(n-1)+2(n-1) nT(n)=(n+1)T(n1)+2(n1)

所以
T ( n ) n + 1 = T ( n − 1 ) n + 2 ( n − 1 ) n ( n + 1 ) \frac{T(n)}{n+1}=\frac{T(n-1)}{n}+\frac{2(n-1)}{n(n+1)} n+1T(n)=nT(n1)+n(n+1)2(n1)

q n = T ( n ) n + 1 q_n=\frac{T(n)}{n+1} qn=n+1T(n),所以 q n = ∑ 2 ( n − 1 ) n ( n + 1 ) = Θ ( H n ) = Θ ( log ⁡ ( n ) ) q_n=\sum \frac{2(n-1)}{n(n+1)}=\Theta(H_n)=\Theta(\log(n)) qn=n(n+1)2(n1)=Θ(Hn)=Θ(log(n))

因此, T ( n ) = Θ ( n log ⁡ ( n ) ) T(n)=\Theta(n\log(n)) T(n)=Θ(nlog(n))

这里其实有一个值得注意的点:

我们可以把快排的所需要的次数用一个关于n的函数表达出来:

f ( n ) = f ( X n − 1 ) + f ( n − X n ) + n − 1 f(n)=f(X_n-1)+f(n-X_n)+n-1 f(n)=f(Xn1)+f(nXn)+n1

这里需要注意的是, X n X_n Xn其实是一个关于n的随机变量。

因此,求快排的时间复杂度实际上是在求 f ( n ) f(n) f(n)的期望:
T ( n ) = E ( f ( n ) ) = E ( f ( X n − 1 ) + f ( n − X n ) + n − 1 ) T(n)=E(f(n))=E(f(X_n-1)+f(n-X_n)+n-1) T(n)=E(f(n))=E(f(Xn1)+f(nXn)+n1)

由于期望的可加性:
T ( n ) = E ( f ( n ) ) = E ( f ( X n − 1 ) ) + E ( f ( n − X n ) ) + n − 1 T(n)=E(f(n))=E(f(X_n-1))+E(f(n-X_n))+n-1 T(n)=E(f(n))=E(f(Xn1))+E(f(nXn))+n1

接下来就可以得到:
E ( f ( X n − 1 ) = ∑ k = 1 n P r ( X n = k ) E ( f ( k − 1 ) ∣ X n = k ) ) E(f(X_n-1)=\sum_{k=1}^n Pr(Xn=k)E(f(k-1)|X_n=k)) E(f(Xn1)=k=1nPr(Xn=k)E(f(k1)Xn=k))

接下来我们进行了一个假设:f(k-1)和 X n = k X_n=k Xn=k无关

方法2:
设置一个随机变量: X i j = 1 ( i − t h 会和 j − t h 进行一次比较 ) , 否则 X i j = 0 X_{ij}=1(i-th\text{会和}j-th\text{进行一次比较}),\text{否则}X_{ij}=0 Xij=1(ith会和jth进行一次比较),否则Xij=0

所以时间复杂度= E ( ∑ 1 ⩽ i < j ⩽ n X i j ) ) = ∑ 1 ⩽ i < j ⩽ n P i j E(\sum_{1\leqslant i<j\leqslant n} X_{ij}))=\sum_{1\leqslant i<j\leqslant n} P_{ij} E(1i<jnXij))=1i<jnPij

这一步利用了E的可加性,它不要求每个事件间是相互独立的。所以问题转换成了求解 P i j P{ij} Pij。也就是第i大的元素和第j大的元素做比较的概率。

这里可以先从两个简单的求一下作为启发: P i , i + 1 P_{i,i+1} Pi,i+1 P 1 , n P_{1,n} P1,n

P i , i + 1 = 1 P_{i,i+1}=1 Pi,i+1=1因为,假设除了 a i a_i ai a i + 1 a_{i+1} ai+1以外,所有的关系我们都知道。那么我们就会得到 a 1 < a 2 < ⋯ < ( a i 和 a i + 1 ) < ⋯ < a n a_1<a_2<\cdots<(a_i\text{和}a_{i+1})<\cdots<a_n a1<a2<<(aiai+1)<<an。不进行比较,我们永远也不知道 a i a_i ai a i + 1 a_{i+1} ai+1哪个大。所以这个比较是一定要做的。

P 1 , n = 2 n P_{1,n}=\frac{2}{n} P1,n=n2原因是:在快速排序的第一轮,我们肯定会把最小和最大的分到两个集合里面分别去求。此后,由于最大和最小的元素在两个集合里面,所以他们就再也没有机会进行比较了。此时 X 1 , n = 0 X_{1,n}=0 X1,n=0。因此,只有在第一轮才有可能比较最小和最大的数。其它情况都不可能。

第一轮,假设选取的数是第3小的,则会:
      
(1 2) | 3 | (4 .. n) 

第1和第2小的在一个集合,后面的在一个集合
这种情况下1和n肯定不会被比较。
当选取的数是第2小到第n-1小的时候同理。

所以只有一种情况1和n会被比较,也就是1或者n被选为那个分割的数的时候。

所以 P i , j P_{i,j} Pi,j如何求?以i=3,j=7为例,看快排的过程一共有三种情况。
P i j = 2 j − i + 1 P_{ij}=\frac{2}{j-i+1} Pij=ji+12

第一轮,假设选取的数是第3小或者第7小的的,则会有三种可能:

最后求和,时间复杂度= ∑ 1 ⩽ i < j ⩽ n P i j = ∑ 1 ⩽ i < j ⩽ n 2 j − i + 1 \sum_{1\leqslant i<j\leqslant n} P_{ij}=\sum_{1\leqslant i<j\leqslant n} \frac{2}{j-i+1} 1i<jnPij=1i<jnji+12

进一步推导得到:
2 ∑ 1 ⩽ i < j ⩽ n − 1 ( 1 2 + 1 3 + ⋯ + 1 n − i + 1 ) = 2 ∑ 1 ⩽ i < j ⩽ n − 1 ( H n − i + 1 − 1 ) 2\sum_{1\leqslant i<j\leqslant n-1} (\frac{1}{2}+\frac{1}{3}+\cdots+\frac{1}{n-i+1})=2\sum_{1\leqslant i<j\leqslant n-1}(H_{n-i+1}-1) 21i<jn1(21+31++ni+11)=21i<jn1(Hni+11)

这个函数正好是 θ ( n l o g n ) \theta(nlogn) θ(nlogn)

最小割

一个无向图G(V,E),选出一组最少的边,把整个图切成两个不连通的分量。

算法:

  1. 随机选一条边
  2. 把这条边的的合并在一起
  3. 删除自环
  4. 重复1-3步,指导只有两个顶点
  5. 剩余的边组成的是一个候选的最小割
orig
   b - c
 /     |
a      |
 \     |
   d _ e

step1: 假设随机选到了a<->b这条边

   ab - c
 / |    |
|  |    |
 \ |    |
   d __ e

step2: 假设随机选了ab<->c这条边
     d
   / |
abc  |
   \ |
     e

成功概率为多少? O ( 1 n 2 ) O(\frac{1}{n^2}) O(n21)

问题:如何证明 ( 1 − 1 n 2 ) n 2 = θ ( 1 ) (1-\frac{1}{n^2})^{n^2}=\theta(1) (1n21)n2=θ(1)
由于 1 − 1 n 2 ≤ e − 1 n 2 1-\frac{1}{n^2} \leq e^{-\frac{1}{n^2}} 1n21en21 n n n是个正整数,所以
( 1 − 1 n 2 ) n 2 ≤ ( e − 1 n 2 ) n 2 = e − 1 = Θ ( 1 ) (1-\frac{1}{n^2})^{n^2} \leq (e^{-\frac{1}{n^2}})^{n^2}=e^{-1}=\Theta(1) (1n21)n2(en21)n2=e1=Θ(1)

实现的复杂度?单次需要 O ( n 2 ) O(n^2) O(n2),想将成功率提高到一个常数,需要重复 n 2 n^2 n2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值