4. Divide-and-Conquer——Introduction to Algorithms Third Edition

来源:互联网 发布:aws免费套餐 centos 编辑:程序博客网 时间:2024/05/21 09:19

Chapter 4. Divide-and-Conquer

要点:Divide-and-Conquer, Maximum-Subarray, Strassen's Matrix Multiplication, Recurrences. (分而治之,最大子集,矩阵乘,递归方程)

  • Divide-and-Conquer
本章引入非常重要的一个算法设计思想:Divide-and-Conquer (分而治之)。

分而治之直观的解释:

  1. Divide,将问题分为几个子问题。
  2. Conquer,这些子问题类比于原问题,可以递归解决。
  3. Combine,将子问题的解合并起来构成原问题的解。

这种思想描述起来很简单,最重要的是如何在实际中应用,下面将会给出两个例子。

  • Maximum-Subarray

问题描述不在赘述。这个问题也在 Programming Pearls Second Edition (编程珠玑) 里用了一章(第八章)分析(我最近在读这本书,今天刚好看了这一章,等第一遍看完,我也会开编程珠玑的笔记专栏)。有两种复杂度为 Θ(n^2) 的方法,参考编程珠玑。

Divide-and-Conquer 方法,复杂度为 Θ(n*lgn)。我们直观的来考虑,把一个数组等分为两份,原数组中和最大的区间不是在左边那份就是在右边那份或者横跨两份。在左边或者在右边都类似于较小集合的原问题,横跨两份的区间只需要从中间向两边扫一遍得到最大和即可。因此这个问题可以用递归方程描述为:T(n) = 2T(n/2)+Θ(n), T(1) = Θ(1)。用下面描述的 master method 可以算出复杂度 Θ(n*lgn)。

Scan 方法,复杂度 Θ(n)。直观的理解,考虑当我们已知 A[0...i] 的解,如何加入元素 A[i+1],得到 A[0...i+1] 的解?很好理解,这个解不是原来 A[0...i] 的解就是区间 [j...i+1]。有了这个规则,我们只需要遍历一遍数组,同时记录当前最优解以及包含尾元素 A[i] 的最优解(假设为区间 [k...i]),考虑 sumA[k...i]+A[i+1] 与 0 的大小关系,如果小于零,说明这个和对后续和会有负影响,故丢弃之,区间更新为 [i+1...i+1];如果大于零,说明这个和对后续和有正影响,区间更新为 [k...i+1]。为了严谨性,这里有一个地方需要证明,即当小于零时,为什么不存在 j∈[k...i] 使得 sumA[j...i+1] 大于零。这里可以形象的将区间 [k...i] 进行分块,A+ 表示连续正数,A- 表示连续负数,那么 A[k...i] 可以描述为:A0+, A0-, A1+, A1-, ..., Am+, Am-,两两分组,每一组的和必然大于零,这是扫描程序的循环不变量,既然所有正数组对的和加上 A[i+1] 还要小于零,那么任意一个位置到 i+1 的和都是小于零的。(参考课后习题4.1-5)CODE

  • Strassen's Matrix Multiplication

其算法复杂度 Θ(n^lg7),这个问题的讨论没有太大的实际意义,除了可以理解分而治之算法。Chapter notes 里给出了详细的讨论,最优的渐近线算法达到了 Θ(n^2.376),而通常使用 Strassen 的方法也只是在规模非常大的情况下,在小规模会切换成直接的方法,就像 STL sort 做的那样。

  • Recurrences

求解递归方程的方法有三种:替代法,递归树,master method。

前两种方法略,但在后面章节的讨论中也会用到。

Master method 主要就是分清楚三种情况,最为简单快捷的方法,也是书中提倡的方法。证明我也没看,太数学了。