5.分治策略 (快速傅立叶变换 最邻近点对 计算逆序 乘法)

分治策略

一、分治策略的复杂度计算

我们可以通过画图来形象的计算复杂度。例如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XszZFXCp-1598865838365)(/Users/zhan/Library/Application%20Support/typora-user-images/image-20200806024122106.png)]

这个图中的算法的复杂度可以用T(n)=2T(n/2)+n来表示,其中第一层的花费可以看作两个子节点的花费加上n,我们将n写在这个根结点的右边,最后我们只要逐层相加即可得到最终的复杂度。

下面给出一个分治算法的复杂度总结(我们称之为Master theorem):

二、计数逆序

问题:对于一串数字,例如1,2,5,4,3,7,假如我们规定这串数字本应该以从小到大的顺序排列,那么现在这串数字就存在着一些逆序。比如有(5,4)(5,3)(4,3)这些逆序。那么能否设计一个算法找到某串数列中逆序的个数呢?

如果用暴力算法,可以发现时间复杂度大概是O(n2),因为对于每个数字都要扫描一遍这个序列。

现在将介绍一种能够在nlogn的时间复杂度内计数逆序的技术。

算法的思路是这样的,假设有一个输入规模为n的数列,每次都递归的将其分成大小相等的两部分,我们不仅要对这两部分分别计算逆序,还要将他们排序。好,现在“递”的过程完成了,那么怎么归呢?我们的办法是对于这被分成的两部分A和B,(A在前B在后,这意味着如果存在a属于A,b属于B,且a>b,那么(a,b)就是一个逆序)我们在归的过程中,假设存在两个指针,一个从A的第一个元素开始,另一个从B的第一个元素开始,每次都让这两个指针指向的元素进行比较,将min(a*,b*)存放到另一个数组C中去,如果我们选中的min=a*,说明a*小于b*之后的所有数,那么将不会产生新的逆序,如果选中的是b*则说明b*要小于a*之后所有的元素,那么a*之后(包括a*)有多少个元素就会产生多少个逆序。

通过这种方式我们就得到了一个排好序的数组C,而且统计出了逆序。

这里我们给出算法的伪代码:


merge—count(A,B)

维护两个指针初始化指向A,B的首元素,设为a,b

count=0

while A,B不空

​ 选择min(a,b)加入到输出数组C

​ if min(a,b)=b

​ count+=A中剩余元素数

​ 被加入到输出数组的那个指针前移

将未空的数组中所有元素加入到C

return count和C


最后我们写递的部分的伪代码:


sort-and-count(L)

if 这个表只有一个元素

​ then 返回0逆序和自己本身

else 把这个表分成大小相等的两半

​ (r1,A)=sort-and-count(A)

​ (r2,B)=sort-and-count(B)

​ (r,L)=merge—count(A,B)

Endif

返回(r+r1+r2,L)


复杂度分析:T(n)=2T(n/2)+O(n)根据master theorem,答案是nlogn。

三、找最邻近点对

问题本身很简单,给定平面上n个点,找到距离最近的两个点。

考虑一种最好想到的递归方法,把点按照个数在平面上分成左右两部分,每部分各有n/2个点。每次都去找这两个部分中最近的点对。

采用这样分治算法的好处(优势)在哪里呢?就是我们立即把一个最复杂的问题边的简单化了:原来我们很难避免不用O(n2)的规模去找最邻近点对,但现在当我们把问题递归到规模只有2的时候(只有2个点),那么这两个点就是最邻近点了,我们可以用O(1)立即得到这一点。这是我们最大的优点。我们假设我们找到了左半边和右半边的最邻近点对,且他们的距离是d。

但是我们面临的问题是如何合并这些结果呢?在某个区域中达到最邻近可不意味着合并之后也是最邻近,换句话说存在某个最近临点,其中一个属于左半边另一个属于右半边。出现这种问题怎么解决呢?

那么首先我们可以确认一点:这样的点对一定出现在距离左右分割线d的区域s之中。

也就是说我们要遍历这个区域s找到最近的点,这件事是不确定的,因为这个区域甚至可能跟整个区域一样大。

但事实是,我们最多只需要遍历15次就能得到结果(这个数字可能会更小):我们如上图所示,在s区域内画出一个包含16个小正方形个字的大正方形,我们可以证明不可能有两个点存在于一个格子内,因为如果是这样的话,他们之间的距离必然小于红色所标注的距离且位于分割线的同一侧,即小于d,这与d是最短距离相悖。我们接着可以证明如果有两个点距离小于d,他们在y坐标上将最多相差15个格子,假设相差超过15个格子,那么他们之间至少相差3行(3d/2),这样的话他们的间距必然大于d不满足条件。所以对于区域s中的某个点只需要遍历至多15次一定能得到结果。

下面给出递归算法伪代码:


closest-pair-rec(Px,Py)(Px是全图中按照x坐标排序的点集,Py类似)

if P的规模≤3

​ 直接找出最邻近点对

构造Qx,Qy,Rx,Ry(Q表示左半边图,R是右半边)

(q1,q2)=closest-pair-rec(Qx,Qy)

(r1,r2)=closest-pair-rec(Rx,Ry)

d=min[(q1,q2),(r1,r2)]

令分割线L为Q中横坐标最大点的横坐标,根据这条线构造一个S区域

构造Sy(O(n)时间)

对于S中每个点s,计算距离s后15个点的间距,并计算出最近的距离d‘

返回min(d,d’)和对应的点对


算法的复杂度是O(nlogn)

四、整数乘法

众所周知,两个n位数进行乘法,我们的复杂度应该是O(n2),那么有没有办法降低这个复杂度呢?

我们的方法是一次计算一半的位数(我们姑且假设是二进制乘法),那么我们有:

我们把规模为n的问题,分成了x1y1、x1y0、x0y1、x0y0四个规模为n/2的子问题,现在我们的时间复杂度呢?T(n)=4T(n/2)+O(n),其实仍然是O(n2)。

但如果我们能够做到 T(n)=3T(n/2)+O(n),我们可以降低复杂度到一个更低的程度。

具体的方法是,计算(x1+x0)·(y1+y0)、x1y1、x0y0这三个规模为n/2的子问题,然后通过相减得到x1y0+x0y1的值(因为我们不必知道他们的具体值,我们只要他们的和)。

这样问题的规模变成了n1.59

五、卷积和fft(快速傅立叶变换)

**什么是卷积?**考虑两个向量a=(a0,a1,a2……an-1),b=(b1,b2,b3……an-1)。那么ab的卷积可以表示为

这个结果是一个具有2n-1个坐标的向量

更形象的表示(卷积的结果就是对角斜线上的项的和):

**怎么计算卷积?**按照卷积的定义去计算的话,我们从上面这个n*n规模的矩阵图就能看出来至少需要n2的时间去计算这个卷积和。但是有一种称为FFT(快速傅立叶变换)的技术可以用O(nlogn)规模的算法完成这个计算。

首先我们要明确一个概念单位的复数根,对于方程xk=1有k个解,这些解分别是e2πji/k(j=0,1,2……k-1)。

我们把A(x)看作a0+a1x1+a2x2+…同理B(x)也是如此。

我们计算卷积的算法主要由以下三步组成:

  • 选择2n个值x1,x2,x2n,并且对于每个j求值A(xj)和B(xj)
  • 对于每个j我们可以用O(1)计算C(xj)因为C(xj)只是等于A(xj)·B(xj)
  • 通过C(x1)、C(x2)……C(xj)的纸获得卷积

对于这三步我们目前只知道第二步可以用O(1)·n=O(n)的时间完成,但是第一步和第三步的时间我们都不清楚。

我们先来看第一步:这里我们用到了分治策略。我们定义T(n)表示一个n-1阶多项式在单位1的所有2n次方根上求值所需要的时间。我们通过这个式子来把他分成两个子问题:A(x)=Aeven(x2)+xAodd(x2

但是我们注意到这和T(n)的子问题还有一点差距,这里虽然计算的阶数变成了原来的一半,但是算的是2n次方根的平方(x2)而不是n次方根。现在我们要证明其实这就是n次方根。因为x=e2πji/2n,那么x2=e2πji/n,实际上就是n次方根。所以其实通过选取这种特殊根的方法把原问题变成了两个规模一半的子问题。而根据上述算式,每次计算A(xj)也只需要花费常数时间去合并,那么总共2n次计算所需复杂度就是O(n)。于是我们得到了熟悉的T(n)=2T(n/2)+O(n)=O(nlogn),至此我们证明了第一步只需O(nlogn)的时间。

接下来看第三步,我们采用一种为逆DFT的方式获得。其步骤与上述fft基本一致,复杂度也是nlogn。这里的结论是:

cj=(1/2n)[C(x0)x2n-j+C(x1)x2n-j+……C(x2n-1)x2n-j] (x0, x1表示的是1的第0,第1个2n次方根)

因此在设计算法的时候也要做相应的改动

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值