在分治策略中,递归地求解一个问题,在每层递归中应用如下三个步骤:
- 分解步骤将问题划分为一些子问题,子问题的形式与原问题一样,只是规模更小。
- 解决步骤递归地求解出子问题,如果子问题的规模足够小,则停止递归,直接求解。
- 合并步骤将子问题的解组合成原问题的解。
当子问题足够大,需要递归求解时,称之为递归情况,当子问题变得足够小,不再需要递归时,递归已经“触底”,进入了基本情况。有时,除了与原问题形式完全一样的规模更小的子问题外,还需要求解与原问题不完全一样的子问题,我们将这些子问题的求解看做合并步骤的一部分。
问题描述:在给出的数组A中寻找出A的和最大的非空连续子数组,这个连续子数组我们称之为最大子数组。(A中的数值应当不全是正数,只有数组A中有负数,这个问题才有意义,否则最大子数组就是A自身)
数组A:13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7。
问题分析:我们现在就按照上面说的三个步骤来解决问题,首先我们要分解,这就意味着要将数组分解成两个规模尽量相等的子数组,也就是对半分,找到数组的中央,比如说mid,然后问题就变成求解数组A[low,mid]和A[mid+1,high]的最大子数组,A[low,high]的任意连续子数组A[i,j]所处的位置必然是下面三种情况之一:
- 完全位于子数组A[low,mid]中,因此low<=i<=j<=mid。
- 完全位于子数组A[mid+1,high]中,因此mid+1<=i<=j<=high。
- 跨越了中点,因此low<=i<=mid< j<=high。
因此,A[low,high]的一个最大子数组所处的位置必然是这三种情况之一。实际上我们所求的最大子数组必然是上面三种情况中和最大的那一种,对于完全位于A[low,mid]和A[mid+1,high]中的情况,我们可以采取递归来求解,因为这两个问题仍然是最大子数组问题,只是规模更小了,所以现在的主要工作就是寻找出跨越了中点的最大子数组,然后跟其它两种情况比较,选出和最大者。
寻找跨越了中点的最大子数组只需要两个循环分别从mid向前向后寻找连续的和最大子数组,然后将其合并,该算法的伪代码如下:
FIND-MAX-CROSSING-SUBARRAY(A,low,mid,high)
left-sum = -∞
sum = 0
for i = mid downto low
sum = sum + A[i]
if sum > left-sum
left-sum = sum
max-left = i
right-sum = -∞
sum = 0
for j = mid + 1 to high
sum = sum