【算法学习笔记十三】随机算法

按照字典中使用的定义,当事件不可预测地发生时,它被认为是随机的。

对象在没有任何计划的情况下被创建时称为随机。

根本的问题是,随机性是否真的存在,或者我们是否只使用这个术语来建模具有未知规律性的对象和事件。

 测试串的相等性

【算法学习笔记十三】随机算法_第1张图片

我们要检查RI和RII是否包含相同的数据。通信协议的复杂性是为了解决这个决策问题而必须在RI和RII之间交换的比特数,我们显然试图将这种复杂性降到最低。 

可以证明,解决此任务的每个确定性通信协议必须在RI和RII之间交换至少n位发送n = 10^{16}位,并确保所有数据都安全地到达另一端是一项非常重要的任务

x=x_1,x_2,...,x_n,x_i\in {0,1},我们表示Number(x)=\sum_{i=1}^{n}2^{n-i}x_i,表示x的二进制字符串;

初始情况:RI有一个n位的序列x, x = x1x2…xn,和RII有一个序列y,由n个比特组成,y = y1y2...yn。

阶段1:RI从区间[2,n^2]中随机均匀地选择一个素数p。

阶段2:RI计算整数s = Number(x)对p取余,并将s和p的二进制表示形式发送给RII。

阶段3:在阅读s和p之后,RII计算q = number (y) mod p。

如果q = s,则RII输出“x = y”。

如果q ≠ s,然后RII输出 “x ≠ y”。

协议的唯一通信涉及提交正整数s和p的二进制表示,因此消息的长度最多为4logn。让我们首先认识到随机方案可能会出错,对于任何输入(x, y),坏素数的个数最多为n - 1。因此错误概率最多是(lnn^2)/n

【算法学习笔记十三】随机算法_第2张图片

当输入x=y相等时,输出一定是正确的;当输出x≠y时,输入时x≠y。

给定x≠y,错误概率P(error)=\frac{bad\ primes}{prim(n^2)},坏素数指的是当对于x≠y的输入,输出错误的结果,即x=y,prim(n^2)\leq n^2的素数个数。例如,当输入15和22,p为7时,输出的结果为15=22,那么此时7就是一个坏素数

素数定理:\lim_{m\rightarrow \infty }\frac{prim(m)}{m/lnm}=1,且prim(m)> \frac{m}{lnm},m>67

当n>9,prim(n^2)> \frac{n^2}{lnn^2}

p对于(x,y)是坏素数\Leftrightarrowp可整除|x-y|< w,w<2^n因子分解w=p_1^{i1}p_2^{i2}...p_k^{ik},p_1<p_2<...<p_k是素数,若k≥n,w\geq p_1p_2...p_k>1*2*...*n=n!>2^n,与已知矛盾,则k

P(error)=\frac{bad\ primes}{prim(n^2)}\leq \frac{n}{n^2/lnn^2}\leq lnn^2/n

随机算法A的错误概率可以通过执行A的多次独立运行而大幅度降低从理论上讲,所有的确定性算法都是绝对正确的,而随机算法可能会出错。但本质是,确定性程序并不是绝对可靠的,因为在它们在计算机上运行的过程中,可能会出现硬件错误,然后它们可能会产生错误的结果。显然,出现硬件错误的概率随着程序的运行时间成比例地增长。因此,快速随机算法比慢速确定性算法更可靠。

不要求算法的输出必须在特定输入的每次运行中都是相同的。放宽条件,算法必须为所有可能的输入正确地解决问题。随机算法在应用于相同的输入时可能会给出不同的结果。但执行时间或空间需求往往小于最优确定性算法。它们非常容易理解和实现。

指示随机变量(Indicator random variables,IRV)

一个转换概率和期望的方便方法。

假设我们有一个样本空间S和一个事件A,那么与事件A关联的指示随机变量I{A}被定义为

I(A)=\left\{\begin{matrix} 1 & if\ A\ occurs\\ 0 & if\ A\ does\ not\ occurs \end{matrix}\right.

引理:给定一个样本空间S和一个事件A,令X_A=I\{A\},那么E[X_A]=Pr\{A\}

生日悖论:

一间屋子里有多少人,才有50%的机会其中两人是在一年的同一天出生的?

球和垃圾箱:

随机把相同的球扔进b箱,一个箱子里有多少个球?在一个给定的箱子里有一个球之前,平均要扔多少个球?要投掷多少个球才能使每个箱子里至少有一个球?

正面:

抛一枚均匀硬币n次,你希望看到的最长的连续正面是什么?

雇佣问题

通过职业介绍所雇佣一名新的办公室助理,机构每天会给你派一个候选人,你会面试那个人,然后决定是否雇佣他,你必须付给中介一笔小额的面试费,要想真正雇佣一个求职者,你必须解雇你现在的办公室助理,并向职业介绍所支付一大笔雇佣费。你承诺在任何时候都要有最适合这份工作的人估计一下这个价格是多少。

HIRE-ASSISTANT(n)
1. best←0
2. for i←1 to n
3.     interview candidate i
4.     if candidate i is better than candidate best
5.     then best←i and hire candidate i
6. endfor

面试和招聘产生的成本:O(nc_i+mc_h)。最坏情况分析的结果是O(nc_h)。但最坏的情况很少发生。

引理:假设候选人以随机顺序出现,算法雇佣助手的总雇佣成本为O(c_hlogn)

X_i=\left\{\begin{matrix} 1 & if\ i\ is\ hired\\ 0 & if\ i\ is\ not \end{matrix}\right.X=X_1+X_2+...+X_n整个过程雇佣的人数。

如果i比1到i-1的人都好,则i会被雇佣,与后面的人无关,E[Xi]=Pr{i被雇佣}=1/i;E[X_i]=E[\Sigma X_i]=\Sigma E[X_i]=\Sigma 1/i=\Theta (logn)

在线雇佣问题

如果我们只有一次机会招聘一个人,如何设计算法来找到最接近的人?在最大限度地减少面试次数和最大限度地提高候选人的招聘质量之间如何取舍?面试完一个人需要马上做决定——雇佣或者不雇佣,如果不雇佣,那么这个人不再有机会,如果雇佣,后面的没有机会面试和被雇佣。

策略:面试并拒绝前k个申请者,然后雇佣比之前所有申请者都优秀的第一个申请者。

ON-LINE-MAXIMUM(k,n)
1. bestscore←0
2. for i←1 to k
3.     if score(i)>bestscore then bestscore←score(i)
4. for i←k+1 to n
5.     if score(i)>bestscore then return i
6. return n

k=n/e,至少有可能雇佣最优秀的应聘者概率为1/e。

证明:

固定k,M(j)=\max_{1\leq i\leq j}score\{i\},表示前j个人中的最高分;S:成功雇佣到最好的;S_i:最好的是第i个且被雇佣。

【算法学习笔记十三】随机算法_第3张图片B_i:最好的人在第i位;O_i:k+1到i-1的人未被雇佣Pr(S_i)=Pr\{B_i\cap O_i\}=Pr\{B_i\}\cdot Pr\{O_i\}(前i个人中最好的出现在前k位)=\frac{1}{ n}\cdot \frac{k}{i-1}Pr(S)=\sum_{i=k+1}^{n}Pr(S_i)=\sum_{i=k+1}^{n}\frac{k}{n(i-1)}=\frac{k}{n}\sum_{i=k}^{n-1}\frac{1}{i}\int_{k}^{n}\frac{1}{x}dx \leq \sum_{k}^{n-1}\frac{1}{i} \leq \int_{k-1}^{n-1}\frac{1}{x}dx,即\frac{k}{n}(lnn-lnk)\leq Pr(S)\leq \frac{k}{n}(ln(n-1)-ln(k-1)),为了使得到最好的人选的概率最大,就要使下界尽可能地大,则k=n/e。

随机算法模型1

随机算法可以看作是部分由随机过程控制的算法。随机算法允许在任何需要的时候抛出“公平”硬币,并且使用抛硬币的结果来决定算法将以何种方式继续工作。随机算法的质量通常以运行时间和可靠性(正确性)的程度来衡量。

该模型认为随机算法A是确定性策略算法的有限集合A1,A2,..,An的概率分布(随机选择其中一个)。将A对输入w为概率空间(S_{A,W},Prob),其中S_{A,W} = {A1,A2,…,An}, Prob为概率分布。通常,Prob是一个均匀概率分布。我们通常倾向于将S_{A,W} = {C1, C2,…,Cn}作为A在w上的所有运行(计算)的集合,其中Ci是第i个确定性算法在w上的计算。

对于一个给定的输入w,随机算法A选择第i个具有概率问题的确定性算法概率为Prob({Ai}),初始i = 1,…n,其余的计算都是完全确定的。

【算法学习笔记十三】随机算法_第4张图片

运行时间(Time)

令Time(Ci)表示计算Ci的长度(时间复杂度)。

A在w的期望时间复杂度:Exp-Time_A(w)=\sum Prob(\{C_i\})\ast Time(C_i)

随机算法A的期望时间复杂度:Exp-Time_A(n)=max\{Exp-Time_A(w)|the\ length\ of\ w\ is\ n\}

随机算法A的时间复杂度:Time_A(n)=max\{Time(C)|C\ is\ run\ of\ A\ on\ an\ input\ of\ length\ n\}

可靠性(Reliability)

定义指示变量X:S_{A,W}\rightarrow \{0,1\},如果Ci在wi上计算得到正确的结果,那么X(Ci)=1,否则X(Ci)=0,i=1,...,n。A对于输入w的成功概率为E[X]=\sum X(C_i)\ast Prob(\{C_i\})=Prob(Event(X=1)),错误概率为Error_A(w)=1-E[X]。A的错误概率为Error_A(n)=max\{Error_A(w)|the\ length\ of\ w\ is\ n\}

注意,我们对时间复杂度度量的定义假设A的所有运行都是有限的,即不允许A进行无限次计算。一般来说,随机算法允许有无限的计算。在这种情况下,测量A的有限计算的期望时间复杂度,并计算运行无限计算的概率,然后将其添加到错误概率(即无限计算的发生被认为是一个错误)。

随机算法模型2(推广)

将随机算法表示为非确定性算法,对于每个非确定性选择都有一个概率分布。

我们可以通过所谓的计算树T_{A,w}来描述随机算法A在输入w上的所有计算(运行)。树的顶点由配置标记的每条路径从根到叶在这棵树对应的计算w。每条边的树是标记的值[0,1]决定从给定的配置选择的概率。

第二个模型是对第一个模型的概括。它用于描述在计算的某些确定部分之后重复地做出随机选择的算法。

随机快排(Randomized Quicksort)

算法 RQS(A):

        输入:给定线性顺序的一组元素。

       步骤1:如果A = {b},则输出“b”。如果|A|≥2,则随机选择一个元素a∈A。

       步骤2:设置A<:=\{b\in A|b<a\},A>:=\{c\in A|c>a\}

       步骤3:输出“RQS(A<),a, RQS(A>)”

没有错误输出的计算。RQS(A)在A上有指数级的许多不同的计算。一个输入上的RQS的计算树不仅非常大(特别是它的宽度),而且它也是非常不规则的。选择合适的随机变量不仅决定了算法分析的成功与否,也决定了分析的难度。Exp-Time_{RQS}(n)=O(nlogn)

证明:

X(C)表示比较数,设S_1<S_2<...<S_n为算法输出,定义X_{ij}(C)=1,S_iS_j比较过,否则=0。

T=\sum_{i=1}^{n}\sum_{j>i}X_{ij}(C)表示总的比较次数,p_{ij}S_iS_j比较的概率,E[T]=\sum_{i=1}^{n}\sum_{j>i}E(X_{ij})=p_{ij}

如果主元从S_1...S_{i-1}或者S_{j+1}...S_n中选取,则S_iS_j会被分到同一个子集,不会影响S_iS_j今后的比较,只要考虑在S_i...S_j中选取主元。

p_{ij}=\frac{|\{S_i,S_j\}|}{|\{S_i...S_j\}|}=\frac{2}{j-i+1}E[T]=\sum_{i=1}^{n}\sum_{j>i}p_ij=\sum_{i=1}^{n}\sum_{j>i}\frac{2}{j-i+1}\leq \sum_{i=1}^{n}\sum_{k=1}^{n-i+1}\frac{2}{k}\leq 2\sum_{i=1}^{n}\sum_{k=1}^{n}\frac{1}{k}=2n\sum_{k=1}^{n}\frac{1}{k}=O(nlogn)

随机选择(Random Select)

算法RSEL (A,k)

       输入:A = {a1, a2, . ., an}, n∈IN−{0},且满足1≤k≤n的整数k。

       步骤1:如果n = 1,则输出“a1”否则随机一致地选择i∈{1,2,…,n};

       步骤2:计算A<:=\{b\in A|b<a_i\},A>:=\{c\in A|c>a_i\}

       步骤3:if | A< |>k,那么RSEL(A<; k);

                 else if|A<| = k−1,则输出“ai”;

                 else RSEL(A>, k−|A<|−1);

显然,算法RSEL(A, k)会在每次运行时计算正确的输出,并且Exp-Time_{RSEL}(A,k)=O(n)

随机算法分类:

决策问题和计算函数的随机算法的标准分类:拉斯维加斯算法,单边误差蒙特卡罗算法,有界误差蒙特卡罗算法,无界误差蒙特卡罗算法。这种分类是基于随机算法的错误概率的种类和大小,与它们的设计方法无关。

拉斯维加斯算法(LAS VEGAS ALGORITHMS)

随机算法A被称为拉斯维加斯算法,它计算一个函数F,对于任意输入x (F的任意参数x), Prob(A(x) = F(x)) = 1。(表示LV算法总是正确的,随机选择,随机快排都属于LV)(而蒙特卡洛算法是会会出错的)

对于拉斯维加斯算法,我们总是研究期望的复杂度。RQS和RSEL,在这两种算法中,我们在最坏情况复杂度和期望复杂度之间有本质的区别。但关键的一点是,预期的复杂性非常接近最有效运行的复杂性。

假设A是一个随机算法,它允许答案是“?”A是函数F的拉斯维加斯算法,对于每个输入x:

(i) Prob(A(x) = F(x)) ≥ 1/2, and

(ii) Prob(A(x) = “?”) = 1 − Prob(A(x) = F(x)) ≤ ½.

\large Protocol\ LV_{10}

我们有两台电脑RI和RII。RI的输入由10个字符串组成,x1, x2, . ., x10∈\{0,1\}^n, RII也有10个字符串,y1, y2, . ., y10∈\{0,1\}^n。任务是估计是否存在j∈{1,…,10},使得xj = yj。如果存在这样的j,则协议必须接受输入((x1, . ., x10), (y1, . ., y10)),如果不存在,则必须拒绝输入。

第一步:选择10个小于n^2的素数(PRIM(n^2));

第二步:xi与对应的素数pi计算余数si,并把所有的素数p和余数发送给RII;

第三步:RII收到后,yi与pi计算余数qi,比较si和qi是否相等,如果不相等,那么对于所有i,xi≠yi,并输出“0”或者拒绝;如果相等,那么将最小的i,记作j,即sj=yj,然后把yj和j返回给RI;

第四步:RI将xj和yj逐位的比较,如果相等则输出“1”,否则输出“?”。

通讯量达到n+40logn+4,这是LV算法。

证明:

1)对于所有的i,xi≠yi,对于pi,有xi mod pi ≠ yi mod pi,概率至少为1-2lnn/n(在上面已经证明),证明Prob(LV(xi,yi)=0)≥1/2;

\geq (1-\frac{2lnn}{n})^{10}=\sum_{i=0}^{10}(-1)^i\binom{10}{i}(\frac{2lnn}{n})^i\geq 1-\binom{10}{1}\frac{2lnn}{n}\geq 1/2,当n足够大。

2)设xj=yj,j是最小的满足等式的下标,必然有xj mod pj = yj mod pj,在第四步会比较xj和yj且接受,当可能j并不会被RII发送给RI,会发送的充要条件是:xi mod pi ≠ yi mod pi ,i=1,...,j-1,即不然正确的j'无法发送到RI。把以上的条件记为Ej。

若j=1,不会出错;

若j>1,Prob(E_j)\geq (1-\frac{2lnn}{n})^{j-1}\geq 1-\frac{2(j-1)lnn}{n},当j=10时取最小值,Prob(LV(xi,yi)=1)≥1-18lnn/n≥1/2;若存在l

如何转换模型中的答案“?”使得模型中所有的输出都必须是正确的结果:

如果T_{A,w}是算法A在输入w上的计算树,那么我们得到了计算树T_{A',w},在挂起的树T_{A,w},A '在w上的计算输出“?”。这种转换的缺点是新算法A '包含无限的计算。另一方面,可以保证,如果它停止,算法A '以正确的结果结束。Exp-Time_{A'}(n)=O(Time_A(n))

【算法学习笔记十三】随机算法_第5张图片

 时间复杂性证明:

A:LV算法;A':可以得到明确结果的算法;

设当输入w,输出?,计算时间最长Time_A(w),令Set_i=\{c\in S_{A',w}|(i-1)Time_A(w)<Time(c)\leq i\cdot Time_A(w)\},恰好运行了i次算法A得到正确结果了,S_{A',w}=\bigcup_{i=1}^{\infty }Set_i,Set_r\neq Set_s,r\neq s。(得到正确结果可能一次,也可能两次...)

运行算法A,i次之后仍未得到正确结果的概率\leq 1/2^i,Prob(\{c\})_{c\in \bigcup_{i=1}^{k}set_i}\geq 1-1/2^k

Exp-Time_{A'}(w)= \sum_{c\in S_{A',w}}Time_{A'}(c)Prob(c)(运行i次的时间以及运行i次出现的概率)

如何转换总是提供正确的结果的拉斯维加斯算法到可能输出" ?“的拉斯维加斯算法:

我们考虑一个计算树T_{A,w},它包含许多短的(有效的)计算,但也有一些相对长的(可能是无限的)计算。当一个计算的运行时间超过了有效计算的时间(即当可能认为正在运行的计算是一个非常长的计算),他可以决定停止这个计算并输出“?”。时间复杂度的约束是什么停止计算?花费时间两倍期望时间的,就足够了停止工作。

【算法学习笔记十三】随机算法_第6张图片

单边误差蒙特卡洛算法(ONE-SIDED-ERROR MONTH CARLO ALGORITHMS)

A是一个随机算法,让(Σ,L)是一个决策问题。A是一个对于L的单边误差蒙特卡罗算法,简称1MC算法。如果

(i)对于每个x∈L, Prob(A(x) = 1)≥1/2,且

(ii) 对于每个x\notin L, Prob(A(x) = 0 ) = 1.

1MC算法就是1MC∗算法,当

(i ')对于每一个x∈L, Prob(A(x) = 1)随着|x|的增长而趋于1。

算法输出1,肯定是正确的;输出0,可能是正确的。

错误概率随计算重复次数的增加呈指数递减(在同一输入上独立运行)。在相同的输入条件下,执行1MC算法A的k次重复工作

(i)复杂度只增加k倍(即以线性方式),

(ii)误差概率以指数速度k趋近于0。(运行k次,只要有1次为1,就输出1,此时一定是对的如果所有的k为0,则输出0,输出0错误的概率< 1/2^k)

用Ak表示1MC算法,该算法在任何输入上由k个独立运行的1MC算法a组成,并且当且仅当至少有一个运行接受该输入。

有界误差蒙特卡洛算法(BOUNDED-ERROR MONTH CARLO ALGORITHMS)

设F是一个函数。一个随机算法A是F的一个有界蒙特卡罗算法, 简称2MC算法,当如果存在一个实数ε,0<ε≤1/2,对于每一个F的输入x,Prob(A(x) = F (x))≥1/2 +ε。(区别于1MC的判定问题,1MC重复运行就是2MC)。

对于任意2MC算法A和任意正整数t,考虑以下随机算法2MC算法A_t

输入:x

步骤1:独立运行t次算法A,保存t次的计算结果\alpha _1,\alpha _2,...,\alpha _t

步骤2: 如果有α出现至少\left \lceil t/2 \right \rceil次,在序列α1, α2, ...,αt中 , 然后 输出 “α” ,否则输出“?” 。

在计算一个错误的结果或" ?” 意味着正确的结果没有出现至少\left \lceil t/2 \right \rceil次。

Time_{A_k}(n)=O(Time_A(n)),运行k次的时间复杂性和运行1次的时间复杂性是同阶的,k与输入规模无关

这个观察的结果是,如果一个渐近速度比任何确定性算法快计算F,然后用一个错误概率低于Ak选择δ也比任何确定性算法更加有效。

无界误差蒙特卡洛算法(UNBOUNDED-ERROR MONTH CARLO ALGORITHMS)

设F是一个函数,如果对于F的每个输入x, Prob(A (x) = F(x))>1/2,我们说一个随机算法A是一个计算F的无边界误差蒙特卡罗算法,简称MC算法。

有界误差蒙特卡罗算法和无界误差蒙特卡罗算法的区别是什么?

为了得到Prob(Ak(x) = F(x)) >1-\delta\delta是一个固定的常数,需要多少次A对x的独立运行?

Time_{A_k}(x)\geq (-ln\delta )/2\cdot 2^{2\cdot |x|}\cdot Time_A(x),(\varepsilon _x=1/2^{|x|})(正确率与输入规模有关)

因此,Ak的运行时间是输入长度|x|的指数,即使在A非常快的情况下。

Protocol UMC

考虑以下 随机的两台计算机之间的通信协议RI和RII,认识语言L_{unequal}={(x,y)|x,y\in \{0,1\}^n,x\neq y,n\in IN}

初始情况:RI有n比特,x = x1x2…xn, RII有n个比特,y = y1y2...yn, n∈IN−{0}。

输入 (x, y) 必须接受,当且仅当 x \neq y。

阶段1:RI随机地选择一个数字j∈{1,2,…,n},并将j和xj发送给RII。

阶段2:RII比较xj和yj。如果 xj \neq yj , RII接受输入(x, y). {RII确信 x \neq y, 即(x, y)∈Lunequal}

如果xj = yj,则RII以1/2-1/(2n)的概率接受(x, y),以1/2 + 1/(2n)的概率拒绝(x, y)。

在每个计算UMC的通信复杂性是\left \lceil log_2(n+1) \right \rceil+1位。

UMC是一种蒙特卡罗协议。

优化问题的随机算法分类

优化问题是一个6元组U=(\Sigma _I,\Sigma _O,L,M,cost,goal),

\Sigma _I是输入字母表

\Sigma _O为输出字母

L⊆\Sigma *_I是可行的语言输入(输入一个只允许有一个合理的解释的)。x∈L称为U的问题实例。

M是一个函数映射L到P(\Sigma _o*),对于每个x∈L, M (x)是集合x可行的解决方案。

cost是代价函数 :\cup _{x\in L}(M(x)\times \{x\})\rightarrow IR^+,映射值都是大于0的

goal∈{minimum, maximum}为目标。

一个可行解α∈M (x)被称为最优问题实例的x,如果cost(\alpha ,x)=Opt(x)=goal\{cost(\beta ,x)|\beta \in M(x)\}

算法A对于任意x∈L,

(1) A(x)∈M(x) (A(x)是问题实例U(x)的可行解)

(2)cost(A(x), (x)) =goal{cost(β,x) |β∈M (x)}。

U=(\Sigma _I,\Sigma _O,L,M,cost,goal)是一个优化问题。

A是U的一致算法,如果对于每一个x∈L, A对x的计算的输出A(x)是x(即A(x)∈M(x))的可行解。

设A是U的一致算法,对于每一个x∈L,我们定义A对x的近似比为Ratio_A(x)=max\{cost(A(x))/Opt_U(x),Opt_U(x)/cost(A(x))\},
其中Opt_U(x)为U的实例x的最优解的代价。

对于任何一个正实数\delta > 1,我们说A是U的\delta近似算法,如果Ratio_A(x)\leq \delta,x∈L。

Algorithm VCA(最小顶点覆盖问题)
Input: A graph G = (V,E).
Phase 1. C := ∅; A := ∅; E’ := E;
Phase 2. while E’ ≠ ∅ do
take an arbitrary edge {u, v} from E’;
C := C ∪ {u, v}; A := A ∪ {{u, v}};
E ‘:= E’ − {all edges incident to u or v};
Output: C

Time_VCA(G) = O(|E|)
Ratio_VCA(G) ≤ 2(近似解不会超过最优解的2倍)
A是极大匹配

随机算法设计的范例

挫败敌人(Foiling the Adversary)

挫败对手常用于解决某些问题

(i)每个确定性算法(策略)都有一些最坏的情况,在这种情况下算法不能有效地计算出正确的输出,

(ii)但存在一类确定性算法,对于每一个问题实例,这类算法中的大多数算法都能有效地计算出正确的结果。

这种方法也称为避免最坏情况输入的方法。

应用挫败对手的方法的艺术在于找到一组合适的确定性算法(策略),这样,对于任何问题实例,大多数算法都能有效地计算出正确的结果。

Hashing

哈希是一种动态数据管理方法。所考虑的数据记录具有唯一的名称,并且可以使用这些名称来请求它们。数据记录的唯一名称称为键(该数据记录的键),整个数据管理由键决定,动态数据管理包括执行以下三个字典操作序列:

Search (T, k): Search for the key (data record) k in the data structure T .

Insert (T, k): Insert the new key (data record) k in the data structure T .

Delete (T, k): Delete the key (data record) k in the data structure T .

动态数据结构,AVL树和B树,使我们能够执行任何这些三种业务Θ(log n)),这是在最坏的情况下以及在平均情况下。哈希的第一个目标是将期望复杂度降低到O(1)。

我们假设我们有内存T,可以直接访问T的每个内存单元,这些内存单元称为槽(slots),而T称为哈希表或直接地址表。大小|T|是T的槽数,我们设置T ={0,1,2,…,m−1},我们有一个大的集合U,叫做全集(universe),包含所有可能的键。

通常情况下,|U|>>|T |,因此不可能将整个全集U嵌入T中,但这并不坏,因为U并不对应于任何实际的数据记录(键),它只是应用程序中可能出现的所有键的集合。因此,与其尝试管理U,我们的目标是在T中保存一个键的实际集合S(数据记录)。集合S由一个经过考虑的应用程序给出,其大小通常可与|T | = m相比较。

我们的任务是保存一组S⊆U的键在T(数据记录)。重点是我们不能影响S的选择,我们没有任何关于S的初步信息,通常,S大约和T一样大,我们确定|S| = n。

任务是确定一个映射h: U→T = {0,1,…, m−1}这样一组S⊆U是均匀“分散”到T。从U到T的函数h称为哈希函数。

【算法学习笔记十三】随机算法_第7张图片

 我们必须在不知道S的情况下选择h,并且在数据管理的过程中,应用Insert (T, k)和Delete (T, k)操作,集合S可能会发生很大的变化。

我们对h提出以下要求:

(i) h可以有效地计算;

(ii)h S⊆U大多数数据集映射到T以这样一种方式,对于i∈{0,1,…,m−1},集合T(i)=\{a\in S|h(a)=i\}的规模为O(|S|/|T|)

为了满足至少(ii),我们至少要有一个哈希函数h它均匀地将U的所有键分布在T中。这种哈希函数的一个例子是h_m(x)= x\ mod\ m定义的函数。

令U = IN为全集,令T ={0,1,…,m−1},m∈IN−{0,1}。设n为正整数,h: U→T为满足Prob(h(x) = i) =1/m的哈希函数。对于T的每一个槽l,

(i)随机S\in P_n(U),P_n(U)=\{S\subseteq U||S|=n\}分配给槽l的元素个数(即 S中h(x) = l的元素x个数)小于n/m+ 1;

(ii)如果n = m,则Prob(来自随机S∈Pn(U)的多个键在第l个槽中)<1/2。

这确保了执行任何字典操作的预期复杂度是O(n/m),对于n=O(m),则是O(1)。这是成立的,因为分配给T的任意槽的键的期望数目小于n/m + 1。这里期望被认为是所有可能集合S的平均值。

(i)对每一个哈希函数h,存在“坏”集合S(例如,一个集合S\subseteq U_{h,i}=\{a\in U|h(a)=i\});

(ii)每一个满足Prob(h(x) = i) =1/m的哈希函数在T中成功地分布了一个随机集合S(以及全集U的大多数子集)的键。

对于h(即每一个确定性哈希)的每一个选择,(i)表示对手可以构造任意坏的输入S,另一方面(ii)表示有许多哈希函数可以确保大多数输入S的最佳可能分布。

根据挫败对手的思想,必须从一组哈希函数中随机选择一个哈希函数,使每个输入集S都均匀分布在T中,具有很高的概率。

我们需要一个哈希函数的集合H从中可以均匀地随机选择h。这意味着我们的概率空间是(H, Prob_H), H的创建方式应该是(H, ProbH)对所有可能的S都是有效的。

定义:设H为从U到T ={0,1,…,m−1}的有限哈希函数集。集合H称为universal,如果U中的每一对元素 x, y , x ≠ y, |{h ∈ H | h(x) = h(y)}| ≤ |H|/m holds, 即, H中的m个哈希函数至多映射x和y到T的同一个槽。

我们立即观察到,在概率空间(h, Prob_H)中,每个全域哈希函数集都满足条件ProbH(h(x) = h(y))≤1/m。

定理:设S⊆U是一个任意的键集,|S| = n。H是一个通用类的哈希函数从U到T = {0,1,…, m−1}。每个x ∈ S和随机选择h ∈ H,集合S_x(h)=\{a\in S|a\neq x,h(a)=h(x)\}的预期规模最多 |S|/|T| = n/m。

定理的结论是,T的任意槽的期望键数小于1 + n/m。因此,假设存在通用哈希函数集,则通用哈希函数集的概念是解决动态数据管理问题的工具。

引理:令U为一个有限集。从U到T的所有函数的类H_{U,T}=\{h|h:U\rightarrow T\}是通用的。

我们不能在实际应用中使用H_{U,T},至少有两个原因。

(1)H_{U,T}太大,无法有效地从H_{U,T}中随机选择h。

(2) H_{U,T}的大多数函数可以被看作是随机映射,因为它们没有比完整表表示更短的描述。这样的函数不能有效地计算。

我们希望有一个这样的哈希函数的泛型H

(i) H很小(至多是|U|的多项式),且

(ii) H的每个哈希函数都可以非常有效地计算。

对于素数p,U={0,1,2,...,p-1},对于任意自然数a,b∈U,我们定义对于每个x∈U,线性哈希函数h_{a,b}: U→T by h_{a,b}(x) = ((ax + b) mod p) mod m。

H^p_{lin}=\{h_{a,b}|a\in \{1,2,...,p-1\},b\in \{1,2,...,p-1\}\},b∈{0,1,. .,p−1}}是一组哈希函数。

定理:对于任意素数p, H^p_{lin}类是哈希函数的一个普遍类,从U ={0,…,p−1}到T ={0, 1,…,m−1}。

指纹识别(Fingerprinting)

基本思想:它是求解等价问题的一种方法。其基本思想是通过这些表示的指纹来比较某些对象的两个(完整)表示。创建指纹的方法是从有限的可能性集合中随机选择的。这背后的主要思想是,对于任何两个不同的对象,大多数创建指纹的方法都保存了两个对象之间的差异。因此,总的来说,我们对指纹提出了以下两个要求。

(i)指纹必须简单和简短,以确保能够有效地比较它们。为了实现这一点,指纹不仅可以是给定对象的压缩表示,还可以是它们的不完整表示。

(ii)尽管物体的大小有限制,但它的指纹必须包含尽可能多的有关该物体的基本信息。

目的是找一个M,这样对任何两个不同的对象O1和O2有足够多的映射f ∈ M且 f(O_1)\neq f(O_2)

集合M可以被视为证明O1 ≠ O2的候选集合,和映射h ∈ M是 (O1) ≠ (O2) 的证明,如果 h(O1) ≠ h(O2).

因此,指纹应用的关键在于在指纹比对的效率(指纹的大小)和M中证人的数量之间寻找一个合理的折衷。

 通信协议:假设RI字符串x\in \{0,1\}^n, RII有一字符串u_i\in \{0,1\}^n,i=1,...,k的集合U=\{u_1,u_2,...,u_k\}。RII不知道任何的字符串x,和RI没有U的任何知识,计算机必须找出是否有x∈U。

问题是,对于U的规模,这种方法仍然提供有效的通信协议。

阶段1:RI一致地随机选择素数p∈PRIM(n²)。

阶段2:RI计算数字s = number (x) mod p并将s和p发送给RII。

阶段3:接收到s和p后,计算机RII计算出qi = Number(ui) mod p (i = 1,…,k)

如果s∈{q1, q2,…,qk},则RII输出“s∈U”。

如果s\notin{q1, q2, 。 ., qk}, 然后 RII 输出 “s \notin U”.

协议PSet的通信复杂度为4·logn

Error_{PSet}(x,U)\leq 1/2,k\leq n/(4lnn)

因此,PSet是一个单边误差蒙特卡罗协议,用于确定k≤n/(4·ln n)时x与U的隶属度。

 Disjointness problem

协议PDisj

初始情况:计算机RI有一集合V = {v1,v2,...,vl}⊆\{0,1\}^n和计算机RII有一组U = {u1,u2,...uk}⊆\{0,1\}^n,正整数l和k。电脑都不知道其他的数据。电脑RI和RII必须决定是否 V ∩ U = ∅ 或 V ∩ U ≠ ∅。

阶段1:RI随机选择一个素数p∈PRIM(n^2)。

阶段2:RI计算数字si = Number(vi) mod p ,i=1, 2,…,l,并将p, s1, s2,…,sl发送给RII。

阶段3:接收到p, s1, s2,…,sl后,计算机RII计算出qm = Number(um) mod p,m = 1,2,…,k。

如果{s1, s2,.  ., sl} ∩ {q1, q2,. ., qk} ≠ ∅,RII 输出 “U ∩ V ≠ ∅”。

如果{s1, s2,…, sl}∩{q1,q2,..., qk} =∅,RII输出“U∩V =∅”。

PDisj是1MC∗协议,对于两集合U, V⊆\{0,1\}^n 的disjointness problem,|U| · |V | = o(n/ ln n),错误率趋于0

Protocol d-R for Equality Problem

初始情况:计算机RI有一个x∈\{0,1\}^n,计算机RII有一个y∈\{0,1\}^n

阶段1:RI从集合PRIM(n^d)= {p | p≤n^d是一个素数}中均匀地随机选择一个素数p。

阶段2:RI计算数字s = number (x) mod p并将s和p发送给RII。

阶段3:接收到s和p后,RII计算q = number (y) mod p。

如果q≠s, 然后RII输出 “x ≠ y”。

如果q = s,则RII输出“x = y”。

通信复杂度2\left \lceil logn^d \right \rceil,只在d中线性增长,而错误概率随d的指数增长趋近于0。当x=y时,不会出错;当x≠y时,Err=|坏素数|/|素数全体|≤n-1/prim(n^d)=dlnn/n^{d-1}

字串判别问题(The Substring Problem)

给定一个文本x = x1x2…xn和文本y = y1y2 ...ym作为字符串在一个字母Σ= {0,1},n≤m,任务是决定是否x是y的子字符串

步骤1:从PRIM(f(n, m))中随机均匀地选择一个素数p。

步骤2:计算Finger_p(x):=Number(x)\ mod\ p

步骤3:依次计算,Finger_p(y(r,n)):=Number(y,(r,n))\ mod\ p对所有r∈{1,2,. .,m−n + 1}(从r开始,长度为n的字符串),并检查是否Finger_p(y(r,n))=Finger_p(x)。对于j∈{1,2,…,m−n+1},使得Finger_p(y(r,n))=Finger_p(x),比较y(j, n)和x。如果y(j, n) = x,则停止并输出“j”。否则继续计算Finger_p(y(j+1,n))。若y(r, n) = x无r,则输出“∅”。

显然,这个算法是拉斯维加斯算法,因为它总是计算正确的输出。

选择f(n,m)=n^2mln(n^2m),得到Exp-time = O(m)。\because Num(y(r+1,n))=2[Num(y(r,n))-2^{n-1}y_r],那么指纹之间也存在关系F_p(y(r+1,n))=[2[F(y(r,n))-2^{n-1}y_r\%p]+y_{r+n}]\%p,计算时间为O(1),所以所有指纹的计算为O(m),而不是O(nm)。

矩阵乘法验证(Verification of Matrix Multiplication)

给定三个(n×n)矩阵A、B和C,决定A·B是否等于C

步骤1:随机选择统一一个向量α∈\{0,1\}^n

步骤2:计算向量β:= A·(B·α)和γ:= C·α

步骤3:如果β=γ,然后输出“A·B = C”,

如果 β ≠ γ 然后 输出 “A · B ≠ C”。

算法的复杂度为O(n^2)。

引理:  A,B, 和 C 是(n × n)矩阵,,使得A · B ≠ C, 那么至少2^{n-1}个α用于识别出 “A · B ≠ C” ,此时的A·(B·α)≠C·α。

引理确保至少一半的向量α 可以识别A· B 和 C。因此, 错误概率在任何输入 (A,B,C) A·B ≠ C 最多是1/2。因此,它是一个1MC的矩阵乘法验证算法。

成功放大(Success Amplification)

基本思想:放大是一种减小误差的方法。简单的方法是在相同的输入上重复整个计算,但是我们只能重复一些计算部分,或者以不同的方式多次重复不同的部分。这样做的目的是要更多地关注那些出错概率比其他部分大的计算部分。

MIN-CUT(参考)

输入:多重统计 G = (V, E, c),其中c: E→IN−{0}决定了G的边的多样性。

约束条件:G的所有可行解的集合为G的所有cut的集合M(G) = {(V1, V2) | V1∪V2 = V, V1∩V2 =∅}。

代价: 对于每cut(V1, V2)∈M(G), cost((V1, V2),G) =∑c(e), e∈S(V1,V2) 和 S(V1, V2) = {{x, y} ∈ E | x ∈ V1 和 y ∈ V2}。cost((V1, V2),G)等于V1和V2之间的边数

目标:最小

著名的MIN-CUT确定性算法的运行时间O(|V|·|E|·log(|V|^2/|E|)

压缩操作Contract(G, e)

对于给定的多图G = (V,E)和一条边e = {x, y}∈E,对边E进行收缩意味着:顶点x和y被一个新的顶点(x, y)替换,多边e = {x, y}以这种方式删除(收缩)(我们不允许任何自己到自己的边),每条边{r, s} r∈{x, y} 和 s\notin{x, y}被一个新的边{ver(x, y) , s}取代, G 剩余的部分保持不变。

将Contract(G, e)可视化,只需将顶点x和y折叠成一个新的顶点。我们用G/{e}表示结果图。

给定一组边F⊆E,收缩的影响并不依赖于收缩的顺序。

【算法学习笔记十三】随机算法_第8张图片

 一个将随机选择的边收缩,直到得到一个恰好有两个顶点V1和V2的多重图。显然V1∪V2 = V, V1∩V2 =∅。因此,(V1, V2)是G的一个切割点,两个顶点V1和V2之间的边数对应于切割点(V1, V2)的代价。我们可以将边{x, y}的收缩看作是说顶点x和y必须位于靠近的切边的同一侧,从而将所有切边的集合限制为一侧有x和y的切边。这样,可能的割集单调地减少,直到它只包含一个cut。

压缩算法:

输入:一个连通多重图G = (V, E, c)

步骤1:对每个顶点v∈V,设置label (v):= {v}。

步骤2:当G有两个以上的顶点时,选择一条边e = {x, y}∈E (G);G:=Contract(G, e);

对于新的顶点z = ver(x, y),label(z):= label (x)∪label (y);

步骤3:如果G = ({u, v},则输出“(label (u), label (v))”和“cost = |E(G)|”

定理:算法压缩是一个随机多项式时间算法,计算n个顶点的多重图G的最小cut,概率至少为2/(n(n−1))

运行n^2/2次计算该算法的最小cut的概率至少为1−1/e。但是算法CONTRACTION_{n^2/2}的复杂度是O(n^4)。

过于复杂的原因是放大法的简单应用,即通过重复整个算法的运行来增加成功的概率。

改进方案Algorithm DETRAN(l):

输入:n条边的多图G = (V, E, c), n∈IN, n≥3。

步骤1:对G执行算法收缩,以得到l(n)个顶点的多图G/F(不是2个顶点结束)。

步骤2:对G/F应用著名的确定性算法,计算G/F的最优割D。

输出:D(第一步随机,第二步随机)

引理:令l: IN→IN为1≤l(n) 时间内运行,它至少找到一个最优解的概率\binom{l(n)}{2}/\binom{n}{2}

定理: 对算法DETRAN_{(n^\left \lfloor 2/3 \right \rfloor)}独立重复运行n^2/(n^{\left \lfloor 2/3 \right \rfloor})^2 的运行时间为O(n^{8/3}),得到最优解的概率至少1-e^{-1}

【算法学习笔记十三】随机算法_第9张图片

Algorithm REPTREE(G)

输入:多图G = (V, E, c), |V | = n, n∈IN, n≥3。

过程:

if n≤6,则确定地计算最小cut

else

       h:=\left \lceil 1+n/\sqrt{2} \right \rceil;

进行两次独立的收缩,得到两个大小为h的多图G/F1和G/F2;

REPTREE (G / F1);

REPTREE (G / F2)

输出REPTREE(G/F1)和REPTREE(G/F2)计算的两个切点中较小的一个。

定理:算法REPTREE工作时间O(n^2logn)和找到最小cut的概率至少1/\Omega (logn)

O((logn)^2)重复次数足以将失败概率降低到随着n的增加而趋于0的函数,总复杂度为O(n^2(logn)^3)

前面不容易出错的少重复几次,后面容易出错的多重复几次。

【算法学习笔记十三】随机算法_第10张图片

丰富的目击者(Abundance of Witnesses)

目击者输入x是额外的信息,有了它的知识,计算x的输出比没有这个信息时要有效得多。我们需要应用大量证人的范例,对于每一个问题实例,一组证人的候选人,其中有大量的证人。这通常意味着候选人集合的基数与集合中的证人数之间的比值是一个常数。然后,只需从候选集合中随机选择一个元素,并以合理的概率获得一个见证就足够了。用这种方法,一个人可以有效地解决问题,即使他或她没有成功地发现所考虑的问题的本质。

寻找目击者素性测试

对于给定的正整数n,判断n是否是合数或素数。

由于n的输入长度是其二进制表示的长度log(n + 1),我们的目标是设计一个运行在时间为O((logn)^c)的算法(c为一个小常数)。

Simple method - NAIV(相当于蛮力搜索)

输入:一个数字n∈IN−{0,1,2}。

I:= 2

PRIM:= TRUE

while I<\sqrt{n}和PRIM= TRUE do

if n mod I=0,那么PRIM:= FALSE;

I:= I + 1

if PRIM= TRUE,那么输出n是素数,否则输出" n是合数"

我们正在寻找一种证人,它能有效地证明“n是合数”这一论断。

证人的适当定义的规定:

(i)“n是合数”这一事实的证人必须提供有效证明这一事实的可能性。

(ii)无论是否是证人,每一个证人候选人都必须能有效地加以核对。

(iii)候选人名单的规定必须使候选人名单中有大量的证人(越多越好)。

设素数m表示所有素数的集合。最简单的想法就是: “number a ∈ {2,...,n − 1 } 是 “n \notin PRIM”的目击者,当且仅当a整除n。

Algorithm  EXP
Input: A real number x and a nonnegative integer n
Output: x^n
    1. y ← 1
    2. Let n be dkdk-1...d0 in binary notation
    3. for j ← k down to 0
    4.     y ← y^2
    5.     if dj=1 then y ← xy
    6. end for
    7. return y
归纳法;时间复杂度为O((logn)^3)
Algorithm  EXPMOD
Input: positive integers a, m and n with m≤n
Output: a^m(mod n)
    1. let the binary digits of m be bk,bk-1,...,b0
    2. c ← 1
    3. for j ← k downto 0
    4.     c ← c^2 (mod n)
    5.     if bj=1 then c ← ac (mod n)
    6. end for
    7. return c

 

费马小定理:如果n是质数,那么对于所有的a!=0 (mod n)有a^{n-1}\equiv 1 (mod n)

a是“n是合数”的证据\Leftrightarrow\ a^{n-1}\%n\neq 1。但a^{n-1}\%n\equiv 1,不能推出n是素数。(伪素数)

Algorithm  PTEST1
Input: A positive odd integer n5
Output: prime if n is prime; otherwise composite
    #等于1推出的素数可能是准确的
    1. if EXPMOD(2,n-1,n)恒等于1 (mod n) then return prime    {probably}
    #不等于1推出合数的结果一定是正确的
    2. else return composite      {definitely}

Algorithm 14.8 PTEST2
Input: A positive odd integer n≥5
Output: prime if n is prime; otherwise composite
    1. a←random(2,n-2)
    2. if EXPMOD(a,n-1,n)恒等于1 (mod n) then return prime    {probably}
    3. else return composite      {definitely}

Carmichael数:对于所有相对于n互素的正整数a都满足上面的定理,但n是合数,最小的Carmichael数是561。

WITNESS(a,n)#判断a是否可以作为证明n是素数的证据
1. let n-1=2^t*u, where t≥1 and u is odd
2. x0←EXPMOD(a,u,n)
3. for i←1 to t
4.     xi←xi-1^2 mod n
5.     if xi=1 and xi-1≠1 and xi-1≠n-1 then return TRUE
6. end for
7. if xt≠1 then return TRUE
8. return FALSE

定理:如果n是奇合数,则证明n是合数的witness至少为(n-1)/2。

Miller-Rabin Algorithm
Input: A positive odd integer n≥5
Output: prime if n is prime; otherwise composite
    1. for j←1 to s
    2.     a←random(2,n-1)
    3.     if WITNESS(a,n) then return composite      {definitely}
    4. end for
    5. return prime      {probably}

定理:对于任意奇数n>2和正整数s, Miller-Rabin犯错的概率最多为2^{-s}

所有有效的随机算法素性测试的方法是基于大量的证人,所以很长一段时间悬而未决的领域是各种各样的证人,证人的确是随机分布在候选集还是只是找不到一个现有秩序的分布。

2002年发现了证人的定义,其性质是:如果p是复合的,那么在最小的候选点中必须总有一个证人证明p是复合的。这一发现导致了在时间O(log^{11}n)运行的确定的质数测试算法。尽管这一结果具有巨大的理论重要性,但这种确定性算法在当前应用中无法与快速随机算法竞争。

 

 

 

你可能感兴趣的:(算法分析)