• 算法导论课后习题解析 第五章


    5.1-1
    如果我们能够比较任意两个应聘者的优劣,那么我们就能够对所有的应聘者按照优劣进行排序,之后按顺序对每个人赋予rank值,这样我们就知道了原来应聘者rank值的序列。

    5.1-2
    要利用Random(0, 1)实现Random(a, b),我们可以把问题转化为实现a+Random(0, b-a)。
    之后可以利用Random(0, 1)来生成二进制下随机数的每一位。由于数的范围是$[0, b-a]$,所以位数的范围是$[1, 1 + \lfloor \lg {(b-a)} \rfloor]$。
    如果生成的数大于b-a,就将其舍去重新生成,直到产生符合要求的数为止。

    Random(a, b)
    	n = 1, s = 2
    	while s <= b - a
    		n = n + 1
    		s = s * 2
    	r = b - a + 1
    	while r > b - a
    		for i = 1 to n
    			r.bit[i] = Random01()
    	return r + a
    

    假设要生成的数最多为n,如果第一次生成的数成功那么每个数的概率为$(\frac 12)^n$;
    如果第一次生成的数失败且失败的概率为p,那么第二次生成数成功时每个数的概率为$p (\frac 12)^n$,所以最终每个数生成的概率为 $$\sum_{i=0}^{\infty} {p^i (\frac 12)^n}$$ 即所得每个数的概率是相同的。
    每一次生成需要的时间为$k=\lfloor \lg (b-a) \rfloor + 1$,第i次生成成功的概率为$1-p$,那么时间期望是 $$\eqalign { E(T) & = \sum_{i=1}^{\infty} { ik \cdot P\{T=ik\}} \\ & = \sum_{i=1}^{\infty} {ik \cdot p^{i-1}(1-p)} \\ & = k(1-p)\sum_{i=1}^{\infty}{i p ^{i-1}} \\ & = \frac {k}{1-p} \\ & = \frac {\lfloor \lg (b-a) \rfloor + 1}{1-p} }$$ 又 $$1 - p = \frac {b-a+1}{2^{\lfloor \lg (b-a) \rfloor +1}} \gt \frac {b-a+1}{2(b-a+1)}= \frac 12$$ $$\Rightarrow E(T) \lt 2(\lfloor \lg (b-a) \rfloor + 1) = O(\lg {(b-a)})$$

    5.1-3
    如果执行两次Biased-Random,出现两个1的概率为$p^2$,出现两个0的概率为$(1-p)^2$,出现一个1和一个0的概率是$2p(1-p)$。 在0、1各一个的情况下,由于先出现1和后出现1的概率是相同的,所以可以利用这一点来设计等概率出现0、1的情况。

    Random01()
    	while true
    		x = Biased-Random()
    		y = Biased-Random()
    		if x != y
    			return x
    

    $$\eqalign { E(T) & = \sum_{i=1}^{\infty} {2p(1-p)(1-2p(1-p))^{i-1})} \\ & = \frac {1}{2p(1-p)}\\ & = O(\frac {1}{2p(1-p)})}$$

    5.2-1
    当第一个应聘者就是最佳人选的时候只需要聘用一次,这时的概率为$1/n$。
    当所有的应聘者按照从劣到优的顺序排列时需要聘用n次,此时的概率为$1/(n!)$。

    5.2-2
    由于第一个应聘者肯定会被聘用,所以第一个应聘者肯定不是最优的,设倒数第i好的应聘者的rank值为i,$r_i$为第i个应聘者的rank值,那么$1 \le r_1 \lt n$, 记第一个应聘者的rank值为i的事件为$A_i$,出现两次聘用的事件为B,那么 $$P(A_i) = \frac {1}{n}$$ 最优的应聘者应该在比第一个应聘者rank值大的应聘者序列中第一个出现,概率为 $$P(B| A_i) = \frac {1}{n-i}$$ 所以总概率为 $$\eqalign {P(B) &= \sum_{i=0}^{n-1} {P(A_i) P(B|A_i)} \\ &= \sum_{i=0}^{n-1} {\frac 1n \frac 1{n-i}} \\ &= \frac 1n \sum_{i=1}^{n-1}{\frac 1i} \\ &= \frac 1n [\ln (n-1) +C]}$$

    5.2-3
    由于出现每个面的几率相同,为$1/n$,所以期望 $$E = \sum_{i=1}^{n} i\frac 1n = \frac {n+1}2$$

    5.2-4
    由于每个人拿到自己的帽子的概率是相同的,为$1/n$,设$A_i = 1$为第i个人拿到了自己的帽子,那么 $$P\{A_i = 1\} = \frac 1n$$ $$E(A_i) = 1 \cdot \frac 1n + 0 \cdot \frac {n-1}n = \frac 1n$$ $$E(A) = E(\sum_{i=1}^n A_i) = \sum_{i=1}^{n} {E(A_i)} = \sum_{i=1}^n {\frac 1n} = 1$$

    5.2-5
    设$A_{ij} = 1$为A[i], A[j]互为逆序对。由于序列是随机的,所以一个元素比另一个大的概率是1/2,即 $$P \{ A_{ij} = 1\} = \frac 12$$ $$E(A_{ij}) = 1 \cdot \frac 12 + 0 \cdot \frac 12 = \frac 12$$ $$\eqalign {E(A) &= E(\sum_{i=1}^{n-1}{\sum_{j=i+1}^{n}{A_{ij}}}) \\ & = \sum_{i=1}^{n-1}{\sum_{j=i+1}^{n}{E(A_{ij})}} \\ & = \sum_{i=1}^{n-1}{\sum_{j=i+1}^{n}{\frac 12}} \\ & = \frac 12 \frac {n(n-1)}2 }$$ 这道题也可以说明插入排序时平均的移动次数为最差时的一半。

    5.3-1
    只要把第一次循环结果作为初始条件即可

    Randomize-In-Place(A)
    	n = A.length
    	swap A[1]  A[Random(1, n)]
    	for i = 2 to n
    		swap A[i]  A[Random(i, n)]
    

    然后初始条件变为序列A[1, 1]以$1/n = (n-1)!/n!$的概率出现A的一种1-permutation,其他和原算法保持不变。

    5.3-2
    这个算法能够产生不同的全排列,但是不能够等可能的产生所有的全排列。例如,当A的长度为3的时候,与原先不同的全排列有n!-1 = 5种,但是该算法第一遍循环的时候放在A[1]的数有两种可能A[2]、A[3],第二边循环的时候放在A[2]的数只有一种可能A[3],所以一共能产生的全排列数为2,小于总的全排列数,故方法错误。

    5.3-3
    这个算法产生的每个全排列的可能性是不同的。例如,当A的长度为3的时候,该算法产生的结果一共有$3^3=27种可能$,但是长度为3的全排列最多有3!=6种,所以这些结果里肯定有相同的全排列。由于产生的结果需要均匀分布(uniform distribution),所以出现的每种全排列的次数应该相同,但是由于27不能被6整除,所以每种全排列出现的可能是不同的,故算法错误。

    5.3-4
    由于产生的随机数范围是[1,n],而全部的位置有n个,所以得到的位置不会重复并且所有位置都可能取到,故在每个位置上的概率相同为$1/n$。但是该算法是错误的,因为每次放到B中的位置是随机的,所以不能保证B中的每个位置都有赋值,故不能保证B是A的全排列。

    5.3-5
    取得全部不同的序列的种数为 $$A_{n^3}^n = \frac {n^3!}{(n^3-n)!}$$ 所有的种数为$(n^3)^n$,所以全部不同的概率 $$P(U) = \frac {A_{n^3}^n}{(n^3)^n} = \frac {n^3!}{(n^3-n)!(n^3)^n} \ge ( \frac {n^3-n}{n^3} )^n = (1-\frac 1{n^2})^n \ge 1-\frac 1n$$

    5.3-6
    如果产生了优先级相同的情况,那么重复生成一组优先级,直至出现全部不同的情况。

    Not-Unique(A)
    	n = A.length
    	sort A to a new array B[1..n]
    	for i = 1 to n - 1
    		if B[i] == B[i + 1]
    			return true
    	return false
    
    Randomize-By-Sorting2(A)
    	n = A.length
    	let P[1..n] be a new array
    	do
    		for i = 1 to n
    			P[i] = Random(1, n*n*n)
    	while Not-Unique(P)
    	sort A, using P as sort keys
    

    假设一次生成出现重复的概率为r,那么每种全排列出现的概率为 $$\sum_{i=i}^{\infty} {(1-r)r^{i-1}\frac 1{n!}} = \frac 1{n!}$$ 假设每次生成优先级并判断重复的时间为$k=O(n \lg n)$,那么总时间的期望为: $$E(T) = \sum_{i=1}^{\infty}{ki \cdot P\{T=ik\}} = \sum_{i=1}^{\infty}{ki (1-r)r^{i-1}}= \frac k{1-r}$$ 由5.3-5可知 $$1-r \ge 1-\frac 1n$$ 所以 $$E(T) = \frac k{1-r} \le \frac k{1- 1/n}=\frac {n}{n-1}k \le 2k = O(n \lg n)$$ 故算法的期望时间复杂度不变。

    5.3-7

    • Initialization: 首先当$m=0,n=n_0$时,我们有$\varnothing$以概率$1/C_{n_0}^0=1$的概率成为$(1,\cdots,n_0)$的一个子集。
    • Maintenance: 接下来,每次迭代开始前我们假定有每种$(1,\cdots,n)$的m-子集S都以为概率$1/C_{n}^m$出现。新的子集可以看作原来的子集新添一个元素。令新子集包含数n+1的事件为B,出现一种包括数n+1的新子集的事件为$X_i$,取出的随机数$i \in S$的事件为C。如果C发生,那么B肯定发生: $$P(C) = \frac {m}{n+1} \qquad P(\overline{C}) = 1-\frac {m}{n+1} \\ P(BC) = P(B|C) \cdot P(C) = 1 \cdot \frac m{n+1} = \frac m {n+1}$$ 如果C不发生,那么数n+1有可能从剩下的n-m+1个数中选出,概率为: $$P(B \overline{C}) = P(B|\overline{C}) \cdot P(\overline{C}) = \frac {1}{n-m+1} \cdot (1-\frac {m}{n+1})=\frac {1}{n+1}$$ 这样就可知B的概率: $$P(B) = P(BC) + P(B \overline{C}) = \frac {m+1} {n+1}$$ 由于新的集合包含了之前的子集S,所以: $$P(X_i|B) = \frac {1}{C_{n}^m} \\ P(X_iB) = P(X_i|B) \cdot P(B) = \frac {m!(n-m)!(m+1)}{n!(n+1)} = \frac {(m+1)!(n+1-m-1)!}{(n+1)!} = \frac {1}{C_{n+1}^{m+1}}$$ $$P(X_i) = P(X_iB) + P(X_i\overline{B}) = \frac 1{C_{n+1}^{m+1}} + 0 = \frac 1{C_{n+1}^{m+1}}$$ 可知当新的集合包含数n+1时,每种可能都以相同概率出现。如果取出的随机数$i \not \in S$,增加的一个数能从剩下的n-m个数中取出,令出现不包括数n+1的新子集的事件为$Y_i$这时: $$P(Y_i|\overline{B}) = \frac {1}{C_n^m} \cdot \frac {1}{n-m}$$ 于是可以算出每种子集出现的概率: $$\eqalign {P(Y_i\overline{B}) & = P(Y_i|\overline{B}) \cdot P(\overline{B}) \\ & = \frac {1}{C_n^m} \cdot \frac {1}{n-m} \cdot \frac {n-m}{n+1} \\ & = \frac {m!(n-m)!(n-m)}{n!(n-m)(n+1)} \\ & = \frac {(m+1)!(n+1-m-1)!}{(n+1)!} \\ & = \frac {1}{C_{n+1}^{m+1}}}$$ $$P(Y_i) = P(Y_iB) + P(Y_i\overline{B}) = 0 + \frac 1{C_{n+1}^{m+1}} = \frac 1{C_{n+1}^{m+1}}$$ 由于当新子集包含和不包含数n+1时每种情况出现的概率都相同为$1/C_{n+1}^{m+1}$,当m和n增1之后满足了下一次迭代的前提。
    • Termination: 最后当迭代结束时,得到的m-子集的每种可能都以$1/C_n^m$的概率出现。

    5.4-1
    要考虑有人和你生日相同,我们可以考虑没有人和你生日相同的情况,一个人和你生日相同的概率为1/365,所以不同的概率为1-1/365,n个人都和你生日不同的概率为$(364/365)^n$,所以我们只要保证: $$(\frac {364}{365})^n \le \frac 12 \\ \Rightarrow n \ge -\frac 1{\lg {(364/365)}} \approx 253$$ 要有至少两个人生日是7.8,那么就要排除掉没有人生日是7.8和只有一个人是7.8的情况,概率为: $$(\frac {364}{365})^n + (\frac {364}{365})^{n-1} = (\frac {364}{365})^{n-1}(1+\frac 1{365})=\frac {366}{365}(\frac {364}{365})^{n-1} \le \frac 12 \\ \Rightarrow n \ge 1 - \frac {1+\lg (366/365)}{\lg {(364/365)}} \approx 255$$

    5.4-2
    显然当投掷次数小于2时不可能有箱子装有两个球,当投掷次数大于b时肯定有箱子装有两个以上的球。 所以我们只要考虑$2 \le k \lt b$的情况。令第i次投掷后任意箱子球数小于2的事件为$B_i$,第i次投掷到空箱子的事件为$A_i$,那么: $$\begin{align} P(B_i) & = P(B_{i-1})P(A_i|B_{i-1}) \\ & = P(B_{i-1})P(A_{i-1}|B_{i-1})P(A_i|B_{i-1}) \\ & = P(B_1)P(A_2|B_1) \cdots P(A_i|B_{i-1}) \\ & = 1 \cdot \frac {b-1}{b} \cdot \frac {b-2}{b} \cdots \frac {b-i}{b} \end{align}$$ 那么第k次投中已有球的箱子的概率: $$\begin{align} P_k & = P(B_{k-1})P(\overline {A_k}|B_{k-1}) \\ & = \frac {k-1}{b} P(B_{k-1}) \\ & = \frac {(k-1)A_b^{k-1}}{b^k} \end{align}$$ 所以投掷次数的期望: $$E = \sum_{k=2}^b {k P_k}$$

    5.4-3
    只需要两两互斥即可,因为只用到了性质 $$P\{b_i=r, b_j=r\} = P\{b_i=r\} \cdot P\{b_j=r\}$$

    5.4-4
    利用随机变量指示器(indicator random variables)来求解,令: $$X_{ijk} = I \{ i,j,k三人拥有相同的生日 \}$$ 设第i个人的生日为$B_i$,一年有m天,则有: $$P\{b_i = r, b_j = r, b_k = r \} = P \{b_i = r\} \cdot P\{b_j=r\} \cdot P\{b_k=r\} = \frac 1{m^3}$$ 可以求得期望 $$E[X_{ijk}] = P\{X_{ijk} = 1\} = \sum_{r=1}^{m} {\frac 1{m^3}} = \frac 1{m^2}$$ 令X为三人生日相同的组数,总人数为n,可知: $$X = \sum_{i=1}^{m} {\sum_{j=i+1}^{m} {\sum_{k=j+1}^{m} {X_{ijk}}}} = \frac {m(m-1)(m-2)} {6n^2}$$ 当$m(m-1)(m-2) \ge 6n^2$时,有三个人生日相同的期望大于1,此时可以求得: $$m = \Theta (\sqrt [3] {n^2})$$

    5.4-5
    这是生日悖论(birthday paradox)的反问题,一个k-string相当于一个每个人的生日组成的序列,n相当于一年的天数,产生一个k-permutation即为每个人的生日都不相同。所以概率为: $$\frac {A_n^K}{n^k}$$

    5.4-6
    首先求空盒子数量的期望,令$X_i = I \{ 盒子i是空的 \}$,那么 $$E[X_i] = P\{ X_i = 1 \} = (\frac {n-1}{n})^n $$ 令X为空盒子的数量,那么 $$E[X] = \sum_{k=1}^n {E[X_k]} = \sum_{k=1}^n {(\frac {n-1}{n})^n} = n(1-\frac 1n)^n$$ 由于 $$\lim_{n\rightarrow \infty}{(1-\frac 1n)^n} = \frac 1e$$ 所以在n较大时空盒子数量的期望接近$n/e$。接下来考虑只有一个球的情况,令$X_i = I \{ 盒子i中有一个球 \}$,那么 $$E[X_i] = P\{ X_i = 1 \} = n(\frac {n-1}{n})^{n-1} \frac 1n = (\frac {n-1}{n})^{n-1}$$ 令X为空盒子的数量,那么 $$E[X] = \sum_{k=1}^n {E[X_k]} = \sum_{k=1}^n {(\frac {n-1}{n})^{n-1}} = n(1-\frac 1n)^{n-1}$$ 由于 $$n(1-\frac 1n)^{n-1} = n\frac {(1-\frac 1n)^n}{1-\frac 1n}$$ 所以在n较大时空盒子数量的期望接近$n^2/e(n-1)$。

    5.4-7
    令$A_{i,j}$表示从第i次开始至少有j个连续的H面出现,那么有 $$P\{ A_{i, \lg n - 2\lg {\lg n}} \} = \frac 1 {2^{\lg n - 2\lg {\lg n}}} = \frac {(\lg n)^2}{n}$$ 所以每个长度为$\lg n - 2\lg {\lg n}$的组都没有出现连续H面次数超过$\lg n - 2\lg {\lg n}$的概率为 $$\begin{align} (1-\frac {(\lg n)^2}{n})^{\frac {n}{\lg n - 2\lg {\lg n}}} & \le e^{-\frac {n/(\lg n - 2\lg {\lg n})-1}{n/(\lg n)^2}} \\ & = O(e^{-\lg n}) \\ & = O(\frac 1n) \end{align}$$

    5-1

    a) 令$X_i$代表第i次Increment操作后计数器增加的数,那么 $$P\{X_i = 0\} = 1 - \frac {1}{n_{i+1}-n_i}$$ $$P\{X_i = n_{i+1}-n_i \} = \frac {1}{n_{i+1}-n_i}$$ $$E[X_i] = 0 \cdot P\{X_i = 0\} + (n_{i+1}-n_i) \cdot P\{X_i = n_{i+1}-n_i \} = 1$$ 令$Y_n$表示n次Increment操作后计数器增加的数,可知期望为 $$E[Y_n] = \sum_{i=1}^n {X_i} = n $$

    b) 求方差(variance)可以用到公式 $$D(\sum_{i=1}^n{X_i}) = \sum_{i=1}^n {D(X_i)}$$ $$D(X) = E[X^2] - E^2[X]$$ 所以 $$\begin{align} D(X_i) & = E[X_i^2] - E^2[X_i] \\ & = 100^2 \cdot \frac {1}{100} - 1 \\ & = 100 - 1 \\ & = 99 \end{align}$$ 求和可得$D(Y_n) = 99n$

    5-2

    a) 我的想法是利用一个长度为n的数组来标记某个元素是否被查看过,并且记录已经查看元素的数量,伪码如下:

    Random-Search(A, key)
    	n = A.length
    	c = 0
    	let B[1..n] be a new array
    	for i = 1 to n
    		B[i] = 0
    	while c < n
    		j = Random(1, n)
    		if A[j] == key
    			return j
    		if B[j] == 0
    			B[j] = 1
    			c = c + 1
    	return NIL
    

    b) 令A为检查元素的次数,那么 $$P\{ A = k \} = \frac {1}{n} (\frac {n-1}{n})^{k-1}$$ 利用几何分布公式可以算出期望为 $$E[A] = \sum_{k=1}^{\infty} {k P\{ A = k \}} = n$$

    c) 令A为检查元素的次数,那么 $$P\{ A = i \} = \frac {k}{n} (\frac {n-k}{n})^{i-1}$$ $$E[A] = \sum_{i=1}^{\infty} {i P\{ A = i \}} = \frac nk$$

    d) 令$X_i$表示i-1个元素被检查过后检查到一个新元素的次数,令$X_{ij}$表示第i-1个元素被检查过后的j次检查发现了新元素,那么 $$P( X_{ij} ) = (\frac {1}{i-1})^{j-1} \frac {1}{n-i+1}$$ $$E[X_i] = \sum_{j=1}^{\infty} {j(\frac {i-1}{n})^{j-1} \frac {n-i+1}{n}} = \frac {n}{n-i+1}$$ 当算法终止时的检查次数为$X=X_1 + X_2 + \cdots + X_n$ $$\begin{align} E[X] & = E[\sum_{i=1}^n {X_i}] \\ & = \sum_{i=1}^{n} E[X_i] \\ & = \sum_{i=1}^n {\frac n{n-i+1}} \\ & = \sum_{i=1}^n {\frac n{i}} \\ & = n(\ln n + C) \\ & = O(n \lg n) \end{align}$$

    e) 由于要找元素出现在每个位置的概率相同为$1/n$,所以期望为 $$E = \sum_{k=1}^n k\frac 1n = \frac {n+1}2$$

    f) 如果有k个数符合要求,那么每个位置出现要找元素的概率为$k/n$,设X为要找的元素第一次出现的位置,那么概率为 $$P\{ X = i \} = \frac {k}{n} (\frac {n-k}{n})^{i-1}$$ 于是可得期望 $$E[X] = \sum_{i=1}^{n-k} {i \frac {k}{n} (\frac {n-k}{n})^{i-1}} \lt \frac nk = O(\frac nk)$$

    g) 如果没有要找的元素,那么将所有元素遍历一遍之后介素,所以运行时间是n。

    h) 可以将第二种方法(Deterministic Search)看作是第三种方法(Scramble Search)的一种特殊情况,其他的情况都是与这种特殊情况对等的,所以同理可得期望运行时间是$O(n/k)$,最差情况为n。

    i) 第二种方式较好,时间复杂度和第三种一致,但是省去了产生全排列的过程。


  • 相关阅读:
    php-instanceof运算符
    windows10-seaslog安装笔记
    [类和对象]1 封装 调用成员函数
    [C++] 拓展属性
    [C++] 引用详解
    [C++] Const详解
    ROS 常用
    win10 ubuntu16双系统安装教程
    [0] OpenCV_Notes
    Ubuntu16.04安装openCV的问题集合
  • 原文地址:https://www.cnblogs.com/Jiajun/p/3080111.html
Copyright © 2020-2023  润新知