算法导论第四章——分治策略

在分治策略中,我们递归地求解一个问题,在每层递归中应用如下三个步骤

  • 分解:将问题划分为一些子问题,子问题的形式和原问题一样,只是规模更小
  • 解决:递归地求解出子问题,如果子问题规模足够小,则停止递归直接求解
  • 合并:将子问题的解组合成原问题的解

当子问题足够大,需要递归求解时,我们称之为递归情况,当子问题足够小,不需要递归时,我们称之为基本情况。有时子问题与原问题不完全一样,我们将这些子问题的求解看成合并步骤的一部分。

1. 最大子数组问题

即给定一个数组,要求找出一个连续的子数组,使得这个子数组的和是所有子数组中最大的。

采用分治策略的求解办法

假定我们要寻找子数组A[low,high]的最大子数组,使用分治技术意味着我们要将子数组划分为规模尽量相等的两个子数组,找到中间位置mid,然后考虑求解两个子数组A[low,mid]A[mid+1,high],A[low..high]的任何连续子数组A[i..j]所处的位置必然是以下三种情况之一:

  • 完全位于子数组A[low..mid]
  • 完全位于子数A[mid+1..high]
  • 跨越了中点,即low<=i<=mid<j<=high

A[low..high]的一个最大子数组必然是这三种子数组中和最大的一个。我们可以递归求解A[low..mid]A[mid+1,high]的最大子数组,然后找出跨越中点的最大子数组,在三者中选取和最大者。

三种情况示例.jpg

我们可以很容易地在线性时间内求出跨越中点的最大子数组。任何跨越重点的子数组都由两个数组A[i..mid]和A[mid+1..j]组成,因此我们只需求出左右两边分别从mid开始的最大子数组,再合并即可。函数返回包含有边界即和的元组。
python代码描述如下:

inf = float("inf")
def findMaxCrossingSubArray(A,low,mid,high):
    leftSum = -inf
    sum = 0
    maxLeft = 0
    maxRight = 0
    for i in range(mid,low-1,-1):
        sum+=A[i]
        if sum>leftSum:
            leftSum = sum
            maxLeft = i
    rightSum = -inf
    sum = 0
    for j in range(mid+1,high+1):
        sum+=A[j]
        if sum>rightSum:
            rightSum = sum
            maxRight = j
    return (maxLeft,maxRight,leftSum+rightSum)

如此,查找跨越中间最大子数组的时间复杂度为Θ(n)

有了该查找算法,我们就可以设计求解最大子数组的分治算法代码了:
python实现如下

def findMaxSumSubArray(A,low,high):
    if high==low:
        return (low,high,A[low])
    else:
        mid = (low+high)//2
        leftLow,leftHigh,leftSum = findMaxSumSubArray(A,low,mid)
        rightLow,rightHigh,rightSum = findMaxSumSubArray(A,mid+1,high)
        crossLow,crossHigh,crossSum  = findMaxCrossingSubArray(A,low,mid,high)
        if leftSum>=rightSum and rightSum>= crossSum:
            return (leftLow,leftHigh,leftSum)
        elif rightSum>=leftSum and rightSum>=crossSum:
            return (rightLow,rightHigh,rightSum)
        else:
            return (crossLow,crossHigh,crossSum)

分治算法的分析

接下来,我们建立一个递归式来描述该过程的运行时间。我们先进行简化,假设原问题的规模为2的幂。
对n=1的基本情况,T(1)=Θ(1)
n>1时,花费的时间为
T(n) = 2T(n/2)+Θ(n),因此该算法的时间复杂度为Θ(nlgn)

2. 矩阵乘法的Strassen算法

常规的矩阵乘法需要Θ(n^3)的时间,但使用Strassen算法,可以将时间优化到Θ(n^{lg7}))

简单的分治算法

为简单起见,当计算C = A×B时,假定都为n*n的矩阵,且n为2的次幂
那么我们可以将每个矩阵都分解为4个n/2 * n/2的矩阵
那么可以将公式写为

公式.PNG

这个公式等价于


公式2.png

我们可以用此公式设计出递归分支算法

伪代码.jpg

在第五行的分解矩阵中,我们并不真正的创建子矩阵,二十使用下标计算来指明一个子矩阵,因此分解仅需Θ(1)的时间。

我们接下来进行递归式的推倒,设运行时间为T(n)
当n=1时,T(1)=Θ(1)
在递归情况下,每次递归需要完成两个 n/2的乘法,因此花费的时间为T(n/2),共调用8词递归,因此时间为8T(n/2)
我们还需进行四次矩阵加法,总时间为Θ(n^2)
因此总的运行时间为
T(n) = 8T(n/2)+Θ(n^2)
解出的时间复杂度为T(n)=Θ(n^3)
因此简单分治并不由于通常的直接计算方法。

Strassen算法

该算法的核心是减少递归树的宽度,即只递归进行7次乘法。
步骤如下:

    1. 与简单分治一样,将矩阵分解为四个子矩阵,花费Θ(1)的时间
  • 2.创建十个n/2的子矩阵,S1,S2...S10用来保存步骤一中创建的两个子矩阵的和或差,复杂度为Θ(n^2)
  • 3.使用步骤一中的子矩阵和步骤二中的子矩阵递归算出7个矩阵积P1,P2...P7
  • 4.通过Pi矩阵的不同组合进行加减运算,计算出C的子矩阵,花费时间Θ(n^2)
    得到的递归式为:
    递归式.jpg

    解出方程,T(n) = Θ(n^{lg7})
    算法细节参见:
    参考链接

3.使用代入法求解递归式

4.使用递归树法求解递归式


这两种方法并不常用,快进到主方法求解递归式

5.用主方法求解递归式

主方法为如下形式的递归式提供了统一的解决办法
T(n) = aT(n/b)+f(n)
其中a≥1b>1是常数,f(n)是渐进正函数,使用主方法只需要记住三种情况。
该递归式描述了将规模为n的问题分解为a个子问题,每个子问题规模为n/b。而函数f(n)包含了问题分解和子问题解合并的代价。

主定理

若我们将n/b解释为int(n/b),那么T(n)有如下渐进界:

  1. 若对于某个常数ε>0,有f(n)=O(n^{logb^{a-ε}}),则T(n)=Θ(n^{logb^a})
  2. f(n)=Θ(n^{logb^a}),则T(n)=Θ(n^{logb^a}lgn)
  3. f(n) = Ω(n^{logb^{a+ε}}),且对于c<1和足够大的n有af(n/b)<=cf(n),则T(n) = Θ(f(n))
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352