痛定思痛,开启算法之路(十五)

    转眼间就要回家过年了,不论是任何原因,最初的计划还是没有完成;回家了,就好好陪陪父母、朋友聚聚吧!
    说实话,一年回家一次的话确实也不容易;没有办法,选择了就应该坦然面对、坚持到底!

6.9 概率算法

    概率算法运行时不仅取决于输入,还与某些随机时间的结果有关;
    举一个例子:从数集Xi.......中中选出“前半段”(即大于或等于中数)中的某个数。对于这个问题的解法,如果要确保选出的数一定位于前半段的话,
那其比较次数一定不可少于n/2,但是大多数情况下我们没有必要保证到那么精确,而是小于一定误差即可,于是一种新的优化方法:
    看一个简单推到:假设随机取到两个数且Xi>Xj,因为随机取得任何数其都有1/2的概率是位于前半段的,则若Xi与Xj均不位于前半段的概率为1/2 * 1/2 =1/4,
又因为Xi > Xj,因为若两者都位于后半段的概率为1/4,且Xi比较大即等同于Xi位于后半段的概率为1/4,推导出较大的Xi位于前半段的概率为1 - 1/4 =3/4 ;
在这里这个结论是可以推广的,即若随机取出的共有k个数,而这k个数中的最大值位于前半段的概率为1 - 2^(-k),当k取值为100的时候,
几乎可以确认其中的最大数一定位于前半段(无论总输入有多长,出错的概率非常小,而性能为最多比较k次)

6.9.1 随机数

生成真正的随机数是困难的且没有太多必要,任何一个确定性函数都会根据某个固定的模式产生数字,他们之间都具有相关性,而一个高效的随机选数算法产生的伪随机数就足够了;

线性同余法:
这里写图片描述
这里写图片描述

6.9.2 着色问题

拉斯维加斯算法:

    书上举得这个例子应该是不难理解的,随机着色求其不能有效着色的概率:对于Si所有元素同着一种颜色概率为2^(-r)(每个Si有r个元素),
对于k个Si集合全都不能有效着色概率为其k倍,带入k的范围可以得出其概率最多为1/2从而得出总有一种有效着色存在:

这里写图片描述

6.9.3 将拉斯维加斯算法变换成确定性算法

    利用加强归纳假设的思想,使算法更加高效、确定,同时除去了加在原始问题上的限制可以适用于更一般的问题。
    问题同上,且得出了一个事实:随即对每个元素着色得到有效着色的概率至少为1/2;
    现在我们向归纳假设上靠拢即缩小规模:取出一个元素,假设我们能对这个元素着蓝色或者红色,
而对于其余的元素进行任意着色扔能得到有效着色的概率不为0;这样我们就可以对n进行归纳,用归纳法对所有元素着色。

这里写图片描述
这里写图片描述

根据如上等式我们得出:

    1)直接归纳假设:在F(n)<1的条件下,我们知道如何为小于n个元素的集合S着色。

最直接归纳就是任取一个元素,对剩余元素进行分析处理(规模缩小1),但是在这里这种方法是行不通的:任取一个元素之后,对于不同的子集可能包含这个元素也可能不包含此元素,于是最初的问题发生了变化,在这里必须加强假设以反映这些变化,如下不是取一个元素而是取一些元素,于是最终的问题发生了等价转化:
这里写图片描述
算法未完,待续;

6.10 查找众数

众数就是在系列中相同元素的个数超过1/2的数(比如选举当中:只有候选人支持票数超过1/2时才可当选,现在的目标就是找到这么一个支持率超过一半的候选人);

对于这个问题有如下几个解法:

1)直接排序然后统计,而排序算法最好情况下其性能为O(n log n);

2)中数查找法:众数肯定等于中数(中数是第n/2小的数,而众数数量超过n/2),其肯定优于全部排完序在统计;

3)线性时间内查找:类似于社会名流问题(采用排除减小规模思想):若Xi不等于Xj,当两个数都被删除后,则原集合当中的众数仍为新集合中的众数(其实这个思想也是很好理解的:对于删除的两个数有可能包含一个众数,有可能两个都不是众数,而对于这两种情况当同时删除两数之后对原集合的众数并不造成影响,因为众数是超过1/2的数,即使每次都删除一个众数,那么剩下的仍是众数);但是对于这个问题的否命题是不成立的:当原集合当中没有众数的时候,每次删除不相等的两个数可能造成新的集合产生了众数(1,2,5,5,3:删除1,2后5成了众数)

其具体实现算法也是很容易理解,如下:首先选取候选众数C为数组第一个元素X[1],记录其出现次数M=1;然后与后面一一比较,相同则M+1不同则M-1,当M=0时选取下一个元素继续作为候选众数再次往后比较;
这里写图片描述
两次扫描比较共(2n-2)次,其运行时间是O(n)

6.11.1 最长递增序列

问题:给定一个由不同整数组成的序列,求它的最长递增序列(可间断取值)

1)归纳假设(首次尝试):给定某个长度小于m的序列,已知道如何求它的某个最长的递增序列。

    对于归纳基础长度为1的序列,结论显然;对于长度为m的序列,先对前m-1个元素求得其中一个LIS,然后考察Xm:
当Xm大于LIS最后一个元素时很显然再加入Xm即可,而不是此种情况时问题则无法继续
(因为LIS可能有多个,而你只知道其中一个,而多个LIS的最后元素与Xm的比较是无法而知的)

2)加强归纳假设(第二次尝试):给定某个长度小于m的序列,知道如何求它的所有的最长递增序列。

    归纳基础显而易见。利用以上相同的方式进行归纳:对所有的LIS都考察与Xm的比较,然后判定是否存在更长的IS,
这解决了上面的问题但是带来了新的问题:当Xm无法与所有的LIS组成更长的IS时,这时应该考虑加入Xm是否会产生更多的LIS即:
之前比LIS短1的IS加上Xm之后就构成了新的多个LIS,要想解决这个问题又需要找出所有的比LIS短1的IS,而要求短1的IS则又需要求短2的IS,如此往复陷入僵局。
说明这个归纳假设过强了。

3)归纳假设(第三次尝试):考虑一下上面的问题:我们其实不必求出所有的LIS,只需求出所有的LIS中最后一个元素最小的一个LIS即可,因为最后一个元素最小的LIS才最有可能在加入Xm之后构成更长的LIS。

给定某个长度小于m的序列,已知道如何求出它的某个最长的递增序列,使得其他的最长递增序列末尾的数都不比这个序列末尾的数小。

然而这只是减少了递归量,并没有去掉递归;只是减少数量而没有触及规模:对于求任一个LIS都需要求短1、短2、、所有的IS来求解;

4)加强归纳假设(第四次尝试):

给定某个小于m的序列,知道如何对于任意 k < m-1 求出BIS(k),如果存在的话.(这里的BIS(k)即上面所说的末尾元素最小的LIS序列)

对于加入Xm可能对于前面所求出的所有BIS(k)都造成影响,所以对于每一次加入的新元素都需要向前进行比较最少)(log m),具体分析如下:
这里写图片描述
6.11.2 查找集合中两个最大的元素

我们应该仔细检查证明过程中是否确实用到了所有的假设;应该设法用更少的假设完成同样的证明;
另外,除非有反例说明已经到达所有可能性的边界,否则我们应该永不满足。

问题:已知集合S有n个元素X1,……Xn,求其中最大的和第二大的元素。

首先利用分治法将含有n个元素的集合S分成大小为n/2的两个子集P和Q:

1)直接归纳假设:假设已知P和Q中最大的和第二大的元素,分别记为p1、p2、q1、q2,然后在求出总的最大和第二大元素:很明显有了这4个数,求出总的S的最大和第二大只需要2次比较即可:首先2个最大元素比较,假如p1>q1,则此时q2可直接舍弃,第二大元素一定取值p2和q1的比较结果:由此的递推关系式为T(2n) = 2T(n) +2及T(2)=1解得T(n)=3n/2-2;尽管这要优于直接进行2n-3次比较(先n-1次找最大,再n-2次找剩下的最大),但仍可继续优化;

2)上面算法存在的瑕疵已经说明了,当p1>q1时,q2可以直接舍弃,也就是没有求出q2的必要;但是在求得时候,我们并不知道p1与 q1那个大,也就是无法确定是该舍弃p2还是q2;这里用到的技巧就是推迟第二大元素的计算,每步只保留一个第二大元素的后选择列表,直到最后一步在求出第二大元素:

归纳假设:给定一个小于n的集合,知道如何找到最大的元素以及第二大元素的一个“短短的”候选者列表。

    算法执行过程:首先集合S分为n/2的子集P和Q,由归纳假设知P和Q的最大元素为p1和q1且第二大元素候选者集合分别为Cp和Cq;比较假设p1>q1,则Cq可直接舍弃,
此时将q1直接并入Cp即可(规模扩大一倍,候选者集合只增加一个元素);性能:对于查找最大元素递归式T(n)=2T(n/2)+1及T(2)=1解得T(n)=n-1,
而对于求第二大元素log n就足够了(因为其元素个数为log n),得出完整的归纳假设:给定一个小于n的集合,知道如何找到最大的元素以及第二大元素的一个候选者集合,
这个集合的元素最多不超过log n个元素。

猜你喜欢

转载自blog.csdn.net/enjoy_endless/article/details/79316482
今日推荐