分治法 divide and conquer
分治算法包含以下步骤:
1、分(divide):将一个大问题分解成若干个子问题,每个子问题的问题规模n更小了,这样就有了好几个待解决的子问题。
2、治(conquer):递归的去解决每个子问题。
3、结合(combine):将每个子问题的解合并成整个大问题的解。
以归并排序(Merge Sort)为例
1、分:将待排序的数组一分为二,该步骤仅花费常数时间
2、治:递归的对每一个子数组进行排序
3、合:将排好序的数组合并起来,该步骤时间花费为O(n)
这样就得到归并排序的时间复杂度递归式:T(n)=2T(n/2)+O(n)=O(nlogn) (求解该递归式参考 如何求解递归式)
二分查找算法(binary search)
二分查找算法的目的是在一个已经排好序的数组中查找一个数x,同样用到了分治策略
1、分:将x与数组的中间元素相比较,时间花费为O(1)
2、治:通过“分”的步骤,得到x所在的子数组序列,于是在该子数组中递归
3、合:nothing
时间复杂度T(n)=T(n/2)+O(1)=O(logn)。这是一个很牛逼的算法,我们知道1K=210,1M=220,1G=230,这就意味着在一千个数中查找一个数,仅需要比较10次,在一百万个数中查找一个数,仅需要比较20次,在10亿个数中查找一个数,仅需要比较30次。
乘方问题(powering a number)
该问题是给定一个数x和一个正整数n,计算x的n次方。朴素算法很简单,就把x乘以n次就可以了,时间复杂度为O(n),现在尝试用分治策略解决该问题。
xn=xn/2*xn/2 如果n是偶数的话,或者xn=x(n-1)/2*x(n-1)/2*x 如果n为奇数的话,这样就将规模为n的问题分解为规模为n/2的问题
1、分:将n次方转换为求[n/2]次方
2、治:递归的求[n/2]次方
3、合:将得到的结果合并为n次方
时间复杂度为T(n)=T(n/2)+O(1)=O(logn) , 对于连乘问题这是最快的方式了。
斐波那契数(Fibonacci numbers)
斐波那契数的定义是:
F0=0
F1=1
Fn=Fn-1+Fn-2
斐波那契数无处不在,当你看到某种水果时,数每次铃声的振动次数时等等,具体可参考“人类文明的斐波那契演进”
朴素算法就是一个递归算法,具体可参考 斐波那契维基百科 那是一个指数级别的算法,时间复杂度为O(xn),其中x是黄金分割数
指数级的算法是个悲剧,多项式的时间才是好的
一种解决办法是自下而上的处理,注意到当计算n-1的斐波那契函数时,n-2的斐波那契数被重复计算了,事实上只需要计算一次就够了
于是,缓存计算过的F0,F1,F2,F3……Fk,这样求Fn的时候只需要将已经求好的前两项相加就可以了,这样运行时间就是线性的T(n)=O(n),但这并不是最好的
另一种解决方法是可以求得斐波那契数的通项公式,参考维基百科,可以看到那是一个求x的n次方的问题,于是正好可以利用上面求乘方问题的分治算法。不过这种计算是不精确的,浮点数的计算有精度问题,用该方法计算的时候很可能丢失一些重要的位。
还有一种算法用到了矩阵的乘法,即平方递归算法
有如下定理:
(后面是矩阵的n次方)
该定理可以用数学归纳法证明,证明过程很简单。这样该问题又变成一个乘方问题,乘法变成了矩阵的乘法,时间复杂度变成了T(n)=O(logn)
矩阵乘法(Matrix Multiplication)
有两个 n行 n列的矩阵方阵A[ai,j],B[bi,j] , 求C[ci,j]=AB , ci,j=Σ ai,kbk,j
简单的方法是直接求每个ci,j,用时O(n),共有n2个项需要求,总的用时就是O(n3),现在用分治法求矩阵乘法
第一种分治策略是用分块矩阵的乘法
将一个n*n的矩阵分成一个2*2的分块矩阵,每个矩阵块儿都是一个n/2*n/2的子矩阵
假设将C分解成r,s,t,u的四块,A分解成a,b,c,d的四块,B分解成e,f,g,h的四块,那么根据矩阵的乘法
r = ae+bg
s = af+bh
t = ce+dg
u = cf+dh
其中的乘法都是矩阵的乘法,每个矩阵的乘法又可以递归的分解成分块矩阵的乘法,总共分解出8个子矩阵的乘法,然后是4个矩阵的加法,矩阵加法的时间复杂度是n2,矩阵加法不是递归的,那么T(n)=8T(n/2)+n2 , 根据求解递归式中的主方法1可得到T(n)=O(n3) , 时间复杂度没有降下来?囧,看来该方法不行。
再来看另一种分治策略:斯特拉森算法
该算法的关键思路是减少乘法的次数,即对于上面的递归式,将8次乘法降低为7次,即通过7次乘法就能得到他们的乘机,神奇!
参考http://book.51cto.com/art/201008/220275.htm
时间复杂度分析:
1、分:将A和B进行分块分解,然后计算一些加减法,时间花费为O(n2)
2、治:用递归的方法计算p1-p7中的乘积
3、和:将这些计算组合起来得到c1-c4,时间花费为O(n2)
T(n) = 7T(n/2)+O(n2) 属于主方法中的方法1,得到T(n)约等于O(n2.81),比立方级的算法好了一点,但也不是最好的。目前已知最好的矩阵乘法算法的时间复杂度大约是O(n2.376),不过该算法只是纯理论上的改进,还无法投入实用。
posted on 2012-06-15 15:02 len_sround 阅读(1343) 评论(0) 编辑 收藏 举报