随机算法是由一个雇佣问题引出的:

假如你要雇佣一名新的办公室助理,但是你先前的雇佣尝试都失败了,你打算找一个雇佣代理。雇佣代理每天给你推荐一个应聘者。你面试这个人,然后决定是否雇佣他,同时你需要付给雇佣代理一定的费用,以便面试应聘者。除此之外,雇佣一个人也需要花费一大笔钱,因为你必须辞掉目前的办公室助理,同时付给雇佣代理一大笔中介费。

你承诺:任何时候都找最合适的人来担任这项职务,因此你决定在面试完应聘者之后,如果该应聘者比目前的办公室助理更合适,就会辞掉当前的办公室助理,然后聘用新的。

同时你愿意为该策略付费,但希望能够估算出该费用。

下面先给出HIRE-ASSISTANT过程的伪代码,该伪代码表示雇佣策略。

假设应聘候选人编号为1…n,该过程中,假设你能在面试完应聘者i之后,可以决定应聘者i是否为你目前见过最佳的人选。

HIRE-ASSISTANT
best = 0
for i = 1 to ninterview candidate iif candidate i is better than bestbest = ihire candidate i

不管是分析费用,还是分析运行时间,采用的方法都是相同的。在任何情形中,我们都是在计算特定基本操作的执行次数。

例如,面试和雇佣都会产生一定的费用,面试费用较低,比如cic_ici​,然后雇佣的费用很高,比如chc_hch​。假设以用有n个应聘者,m个被雇佣的人,那么这个算法的总费用为O(cin+chm)O(c_in+c_hm)O(ci​n+ch​m)​​​​​。由于面试产生的费用总是cinc_inci​n,因此我们只关注分析chmc_hmch​m就可以了,也就是雇佣的费用。

我们很容易就知道,上述的策略是极其依赖于输入序列的,不同的输入序列,会产生不同的情况,运行时间也就不同。如果应聘者的质量严格递增的话,你就需要雇佣n次,总的费用就是O(chn)O(c_hn)O(ch​n)​​​​​​​​​​​。这个时候我们就需要讨论平均情况下的运行时间了,我们可以假设每个应聘者是随机出现的。随机出现就意味着所有应聘者之间存在着一个全序关系,那么一共就有n!n!n!种排列的可能,每一种序列等概率出现。

但是大多数情况下,我们并不知道应聘者是不是随机出现的,因此这个时候可以在输入和算法之间加入一个随机数生成器,那么这个时候我们可以称这个算法是随机的。(在实践中,大多数编程环境会提供一个伪随机数生成器,它是一个确定性算法,返回值在统计上看起来是随机的。)

当分析一个随机算法的运行时间时,我们以运行时间的期望值来衡量,一个随机算法的运行时间称为期望运行时间;当概率分布发生在算法的输入的时候,我们讨论的是平均情况运行时间

指示器随机变量

我们经常采用指示器随机变量来进行分析,它为概率和期望之间的转换提供了一个便利的方法。

给定一个样本空间SSS和一个事件AAA,那么事件AAA对应的指示器随机变量I(A)I(A)I(A)定义为:
I{A}={1如果A发生0如果A不发生I\{A\}= \left \{ \begin{aligned} &1 \quad \text{如果A发生}\\ &0 \quad \text{如果A不发生} \end{aligned} \right. I{A}={​1如果A发生0如果A不发生​
举个例子,假设我们来确定抛一枚标准硬币时 正面朝上的期望次数。样本空间S={T,F}S=\{T \,, F\}S={T,F}​​​,TTT​​表示正面朝上,FFF​​表示反面朝上,其中Pr{T}=Pr{F}=1/2Pr\{T\}=Pr\{F\}=1/2Pr{T}=Pr{F}=1/2​​。接下来定义一个指示器随机变量XTX_TXT​​,对应硬币朝上的事件TTT​​​。​这个变量是计数抛硬币时正面朝上的次数,如果正面朝上则值为1,否则为0。
XT=I{T}={1如果T发生0如果F发生X_T=I\{T\}= \left \{ \begin{aligned} &1 \quad \text{如果T发生} \\ &0 \quad \text{如果F发生} \end{aligned} \right. XT​=I{T}={​1如果T发生0如果F发生​
所以在一次抛硬币的时候,正面朝上的期望次数就是指示器变量XTX_TXT​的期望值:
E[XT]=E[I{T}]=1∗Pr{T}+0∗Pr{F}=1/2E[X_T]=E[I\{T\}]=1*Pr\{T\}+0*Pr\{F\}=1/2 E[XT​]=E[I{T}]=1∗Pr{T}+0∗Pr{F}=1/2
因此,抛一枚硬币的时候,正面朝上的期望次数为1/21/21/2。

一个事件A对应的指示器随机变量的期望值等于事件A发生的概率。

给定一个样本空间S和事件A,设XA=I{A}X_A=I\{A\}XA​=I{A}​,那么E[XA]=Pr{A}E[X_A]=Pr\{A\}E[XA​]=Pr{A}​。(这里就不证明了,证明过程可以去看算法导论)

指示器随机变量看起来很麻烦,但是在分析重复随机试验的时候是非常有用的。

接下来我们使用指示器随机变量来分析这个雇佣问题。

XXX对应我们雇佣新的办公室助理的次数,XiX_iXi​对应第iii​个应聘者被雇佣 这个指示器随机变量:
Xi=I{i被聘用}={1应聘者i被聘用0应聘者i未被聘用X_i=I\{i\text{被聘用} \}= \left \{ \begin{aligned} &1 \quad \text{应聘者}i\text{被聘用} \\ &0 \quad \text{应聘者}i\text{未被聘用} \end{aligned} \right. Xi​=I{i被聘用}={​1应聘者i被聘用0应聘者i未被聘用​

X=X1+X2+...+XnX=X_1+X_2+...+X_n X=X1​+X2​+...+Xn​

现在我们分析一下HIRE-ASSISTANT执行的效率:

我们在上文已经假设每个应聘者是随机出现的,那么前iii​个应聘者中的任意一个都等可能的是目前最有资格的,那么应聘者iii​比其他应聘者更有资格的概率是1/i1/i1/i,也就是应聘者iii会以1/i1/i1/i​​的概率被雇佣。
E[Xi]=Pr{应聘者i被雇佣}=1/iE[X_i]=Pr\{\text{应聘者}i\text{被雇佣}\}=1/i E[Xi​]=Pr{应聘者i被雇佣}=1/i

E[X]=E[∑i=1nXi]=∑i=1nE[Xi](期望的线性性质)=∑i=1n1/i=ln(n)+O(1)(调和级数)\begin{aligned} E[X] &= E[\sum_{i=1}^{n}X_i] \\ &=\sum_{i=1}^n E[X_i] \quad \text{(期望的线性性质)} \\ &=\sum_{i=1}^n 1/i \\ &=ln(n)+O(1) \quad \text{(调和级数)} \end{aligned} E[X]​=E[i=1∑n​Xi​]=i=1∑n​E[Xi​](期望的线性性质)=i=1∑n​1/i=ln(n)+O(1)(调和级数)​

根据上述分析的结果,我们可以知道,尽管我们需要面试nnn个人,但平均起来,实际上大约只雇佣了他们之中的ln(n)ln(n)ln(n)个人。

假设应聘者是随机次序的,那么算法HIRE-ASSISTANT总的雇佣费用平均情况下为O(chlnn)O(c_hlnn)O(ch​lnn)。

我们之前也说过,我们不能限制输入的随机性,但是我们可以加一个中间层,不管输入的序列是什么,都产生一个均匀随机的序列,这样执行就不依赖于输入了,而是依赖于随机选择。

RANDOMZED-HIRE-ASSISTANT
randomly permute the list of candidates//随机输入
best = 0
for i = 1 to ninterview candidate iif candidate i is better than bestbest = ihire candidate i

我们只是做了一个简单的改变,很明显看出,这个随机算法的性能,与假设应聘者以随即次数出现所得结果是一样的。因为和之前相比,只是去掉了假设,换成了使用随机算法使输入随机化。

很多随机算法通过给定输入 变换排列以使输入随机化。接下来讨论两种随机方法,并给予证明。(我用我贫瘠的数学知识,我太废了)

第一种:为数组的每个元素A[i]A[i]A[i]赋予一个随机的优先级P[i]P[i]P[i],然后根据优先级对数组AAA​中的元素进行排序。就是我们常说的置换策略。

例如:A={1,2,3,4}A=\{1,2,3,4\}A={1,2,3,4}​​​​,随机的优先级P={45,23,96,12}P=\{45, 23, 96, 12\}P={45,23,96,12}​​​​(数值越小,优先级越高),那么就会产生一个数组B={4,2,1,3}B=\{4,2,1,3\}B={4,2,1,3}​​​​​。这个过程称为PERMUTE-BY-SORTING:

PERMUTE-BY-SORTING
n = A.length
let P[1...n] be a new array
for i = 0 to nP[i]=RANDOM(1,n^3)
sort A, using P as sort keys

这里使用n3n_3n3​是为了让PPP中所有的优先级尽可能唯一,现在假设所有的优先级都唯一

那接下来我们证明这个过程能产生一个均匀随机排列,即该过程可以等可能地产生数字1~n的每一种排列。换种说法就是,需要证明每一种排列发生的概率是1n!\frac{1}{n!}n!1​。

先考虑每个元素A[i]A[i]A[i]​分配到第iii​个的特殊排列开始,其实就是A=BA=BA=B​。假设EiE_iEi​​代表元素A[i]A[i]A[i]​分配到第iii​个这个事件,则对所有的iii​,该事件发生的概率是:
Pr{E1∩E2∩⋅⋅⋅∩En−1∩En}=Pr{E1}∗Pr{E2∣E1}∗Pr{E3∣E2∩E1}⋅⋅⋅Pr{En∣En−1∩⋅⋅⋅∩E1}\begin{aligned} &Pr\{E_1 \cap E_2 \cap···\cap E_{n-1} \cap E_n\} \\ \\ &=Pr\{E_1\}*Pr\{E_2|E_1\}*Pr\{E_3|E_2 \cap E_1\}···Pr\{E_n|E_{n-1}\cap···\cap E_1\} \end{aligned} ​Pr{E1​∩E2​∩⋅⋅⋅∩En−1​∩En​}=Pr{E1​}∗Pr{E2​∣E1​}∗Pr{E3​∣E2​∩E1​}⋅⋅⋅Pr{En​∣En−1​∩⋅⋅⋅∩E1​}​
其中Pr{E1}Pr\{E_1\}Pr{E1​}是从一个nnn个元素的集合中选取一个优先级最高(即数值最小)的概率,那么Pr{E1}=1/nPr\{E_1\}=1/nPr{E1​}=1/n。Pr{E2∣E1}Pr\{E_2|E_1\}Pr{E2​∣E1​}​就是从剩下的n−1n-1n−1个元素中选取一个优先级最高的概率,那么Pr{E2∣E1}=1/(n−1)Pr\{E_2|E_1\}=1/(n-1)Pr{E2​∣E1​}=1/(n−1)。以此类推,Pr{Ei∣Ei−1∩...∩E1}=1/(n−i+1)Pr\{E_i|E_{i-1}\cap...\cap E_1\}=1/(n-i+1)Pr{Ei​∣Ei−1​∩...∩E1​}=1/(n−i+1)。因此,
Pr{E1∩E2∩⋅⋅⋅∩En−1∩En}=(1n)(1n−1)...(1n−i+1)...(12)(11)=1n!Pr\{E_1 \cap E_2 \cap···\cap E_{n-1} \cap E_n\}=\bigg( \frac{1}{n} \bigg) \bigg( \frac{1}{n-1} \bigg)...\bigg( \frac{1}{n-i+1} \bigg)...\bigg( \frac{1}{2} \bigg)\bigg( \frac{1}{1} \bigg)=\frac{1}{n!} Pr{E1​∩E2​∩⋅⋅⋅∩En−1​∩En​}=(n1​)(n−11​)...(n−i+11​)...(21​)(11​)=n!1​
现在已经证明这个特殊的排列的发生的概率是1n!\frac{1}{n!}n!1​,现在需要扩展到其他的排列。如果EiE_iEi​代表元素A[i]A[i]A[i]分配到第ξ(i)\xi(i)ξ(i)小的事件,A[i]A[i]A[i]被分配到了jjj位置上,上述的证明同样适用。因此,如果要计算得到任何特定排列的概率,该计算与前面的计算完全相同,于是得到此排列的概率为1n!\frac{1}{n!}n!1​。

这样我们就证明了PERMUTE-BY-SORTING过程可以产生输入的均匀随机的排列。

第二种方法,就是原地排列给定数组。在进行第iii次迭代的时候,元素A[i]A[i]A[i]是从元素A[i]A[i]A[i]到A[n]A[n]A[n]中随机选取的,第iii次迭代之后,A[i]A[i]A[i]不再改变。 RANDOMIZE-IN-PLACE过程的时间复杂度为O(n)O(n)O(n)​。

RANDOMIZE-IN-PLACE
n = A.length
for i = 1 to nswap A[i] with A[RANDOM(i,n)]

接下来我们我们来证明这个过程可以产生均匀随机排列,和之前一样,证明每个排列生成的概率为1n!\frac{1}{n!}n!1​,证明方位使用的是循环不变式。

循环不变式和数学中的数学归纳法一样,都是一种演绎推理法,用于理解和证明算法的正确性。

循环不变式不是一个狭义上的一个式子,而是一个命题,在算法的起始状态、运行过程中和算法而技术时始终保持为真的一个命题。

循环不变式的三条性质:

  • 初始化:循环的第一次迭代之前,它为真。

  • 保持:如果循环的某次迭代之前它为真,那么下次迭代之前它仍为真。

  • 终止:在循环终止时,不变式为我们提供一个有用的性质,该性质有助于证明算法时正确的。

注意:循环不变式的前两条性质类似于数学归纳法,证明了一个基本情况和一个归纳步。此外,终止性不同于数学归纳法的做法,在归纳法中,归纳步是无限地使用的,这里当循环终止的时候,归纳随之终止。

对于RANDOMIZE-IN-PLACE,在进行第iii迭代之前,对每个可能的(i−1)(i-1)(i−1)排列(有(n−i+1)!(n-i+1)!(n−i+1)!种),那么在子数组A[1...i−1]A[1...i-1]A[1...i−1]​​包含某个(i−1)(i-1)(i−1)排列的概率为(n−i+1)!/n!(n-i+1)!/n!(n−i+1)!/n!。

我们只需要证明,该循环不变式在第1次迭代之前为真,同时循环的每次迭代能够维持此不变式,并且当循环终止时,这个不变式能够得到证明算法正确的有用性质或结果。

初始化: 在第1次迭代之前,此时i=1i=1i=1,对于循环不变式来说,子数组A[1...0]A[1...0]A[1...0]包含0排列的概率为n!/n!=1n!/n!=1n!/n!=1。我们很容易知道,子数组A是一个空数组,0排列也是空的,没有元素,那么该子数组包含0排列的概率必然为1。因此,该循环不变式在第一次迭代之前是为真的。

保持: 我们假设在进行第iii次迭代之前,每种可能的(i−1)(i-1)(i−1)排列出现在子数组A[1...i−1]A[1...i-1]A[1...i−1]中的概率为(n−i+1)!/n!(n-i+1)!/n!(n−i+1)!/n!。我们要证明在第iii次迭代之后,每种可能的iii排列出现在子数组A[1...i]A[1...i]A[1...i]中的概率为(n−i)!/n!(n-i)!/n!(n−i)!/n!,依然保持循环不变式。

我们先考虑一个特殊的iii​排列,{x1,x2,...,xi}\{x_1,x_2,...,x_i\}{x1​,x2​,...,xi​}​,这个排列中包含一个(i−1)(i-1)(i−1)​​排列 {x1,x2,...,xi−1}\{x_1,x_2,...,x_{i-1}\}{x1​,x2​,...,xi−1​},接着算法会在A[i]A[i]A[i]中放入xix_ixi​。

设E1E_1E1​表示前i−1i-1i−1次迭代已经在A[1...i−1]A[1...i-1]A[1...i−1]中构造了(i−1)(i-1)(i−1)排列的事件,根据循环不变式,Pr{E1}=(n−i+1)!/n!Pr\{E_1\}=(n-i+1)!/n!Pr{E1​}=(n−i+1)!/n!。

设E2E_2E2​表示第iii次迭代在位置A[i]A[i]A[i]放置xix_ixi​的事件。当E1E_1E1​和E2E_2E2​都恰好发生的时候,{x1,x2,...,xi}\{x_1,x_2,...,x_i\}{x1​,x2​,...,xi​}排列会出现在A[1...i]A[1...i]A[1...i]中,因此:
Pr{E2∩E1}=Pr{E2∣E1}∗Pr{E1}=1n−i+1∗(n−i+1)!n!=(n−i)!n!\begin{aligned} Pr\{E_2\cap E_1\}=Pr\{E_2|E_1\}*Pr\{E_1\}=\frac{1}{n-i+1}*\frac{(n-i+1)!}{n!}=\frac{(n-i)!}{n!} \end{aligned} Pr{E2​∩E1​}=Pr{E2​∣E1​}∗Pr{E1​}=n−i+11​∗n!(n−i+1)!​=n!(n−i)!​​
这符合循环不变式。

终止: 终止的时候,i=n+1i=n+1i=n+1,子数组A[1...n]A[1...n]A[1...n]是一个给定n排列的概率为(n−(n+1)+1)/n!=1!/n!=1(n-(n+1)+1)/n!=1!/n!=1(n−(n+1)+1)/n!=1!/n!=1。

综上所述,RANDOMIZE-IN-PLACE可以产生一个均匀随机排列。

从上面一大堆我们可以知道,随机算法使得算法不再依赖于输入,通常是解决一个问题最简单、最有效的方法。

Randomized algorithms(随机算法)相关推荐

  1. 算法设计技巧与分析(八):随机算法(Randomized Algorithms)

    文章目录 随机算法(Randomized Algorithms) 一.随机选择(Randomized Selection) 二.测试字符串相等性(Testing String Equality) 三. ...

  2. [题集]ADS13 Randomized Algorithms

    1.Let a=(a1,a​2,-,a​i,-,aj,-,an) denote the list of elements we want to sort. In the quicksort algor ...

  3. [PKUWC2018]随机算法

    题意:https://loj.ac/problem/2540 给定一个图(n<=20),定义一个求最大独立集的随机化算法 产生一个排列,依次加入,能加入就加入 求得到最大独立集的概率 loj25 ...

  4. Dubbo中基于权重的随机算法

    转载自dubbo源码解析-LoadBalance dubbo的源码地址:https://github.com/alibaba/dubbo Dubbo中的RandomLoadBalance采用基于权重的 ...

  5. labuladong的算法小抄pdf_随机算法:水塘抽样算法

    读完本文,你可以去力扣拿下如下题目: 382.链表随机节点 398.随机数索引 -----------我最近在 LeetCode 上做到两道非常有意思的题目,382 和 398 题,关于水塘抽样算法( ...

  6. 算法导论之概率分析和随机算法

    在问题的分析中应用概率技术称为概率分析,前期是对所有可能的输入集合可以做假定.如果无法对输入分布做合理性建模,如果一个算法的行为不只是由输入决定,同时也由随机数生成器所产生的数值决定,则为随机算法.行 ...

  7. java 权重_java实现权重随机算法

    权重随机算法在抽奖,资源调度等系统中应用还是比较广泛的,一个简单的按照权重来随机的实现,权重为几个随机对象(分类)的命中的比例,权重设置越高命中越容易,之和可以不等于100: 简单实现代码如下: im ...

  8. 使用轮转算法求时间片_彩票调度算法,让进程们拼手气? --当操作系统遇上随机算法...

    这篇文章主要想介绍下彩票调度(个人觉得这个算法非常有意思~ ),还有随机算法相对传统算法的一点优势,毕竟现在绝大多数算法都是追求确定性,尤其在操作系统,大家都希望一切可控,所以随机算法的出现听起来有些 ...

  9. 浅浅地谈一下随机算法【poj2454】【poj3318】

    随机算法我也只是稍微接触了一下,就是想写篇博客自己稍微总结一下 其实随机算法也算是一个玄学吧,运气不好还是会wa.但是我们知道,计算机可以在短时间内计算大量的数据,所以碰到正确答案的概率还是挺大的. ...

最新文章

  1. 寒冰linux视频教程笔记8 系统监控
  2. 网络营销外包立足用户角度完成企业网站网络营销外包优化
  3. PHP 安全问题入门:10 个常见安全问题 + 实例讲解
  4. Python列表的常用方法
  5. 直播报名 | 用户中台建设实践解析
  6. 人生财富值得珍藏的文字
  7. 【图嵌入】Graph Embedding 方法之 LINE 原理解读
  8. java学习(60):java最终类(了解)
  9. 解决VM虚拟机中ubuntu系统上不了网的问题
  10. 波卡生态DAO基础设施完成150万美元战略融资
  11. mysql闩_Oracle闩:Cache Buffers chains
  12. python 中关于系统路径的事项;
  13. PMP中英文术语对照
  14. 【jq练习】基本选择器
  15. 【win10压缩卷问题解决】:无法将卷压缩到超出任何不可移动的文件所在点
  16. 卡西欧计算机设置参数,【卡西欧 fx-991CN X 中文函数计算器使用总结】参数|功能|显示|计算_摘要频道_什么值得买...
  17. 清梦_飘云羽逸_新浪博客
  18. 2009.7.30-8.4生活小结
  19. (三)对图像进行Gauss高斯平滑处理
  20. pandas中的concat操作

热门文章

  1. access的查询导致长文本数据缺失_Access常见错误及解决方案
  2. 2021小微企业补贴条件
  3. 颅骨钢板系统的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  4. 正则表达式 同时验证手机号码和固定电话号码
  5. Java之Excel导出工具类使用教程
  6. 将才与帅才的12个差别!你是哪个
  7. 你离拍出好的雪景作品,还有多远? @教摄影
  8. 三段式电流保护 Matlab仿真
  9. 日复一日的重复性工作,想跳槽 ?
  10. 2017年第3届上海国际零售业设计与设备展会刊(参展商名录)