分治策略——最大子数组的问题(附伪代码)

什么是最大子数组?

分治策略——最大子数组的问题(附伪代码)_第1张图片
如图所示,为寻找数组A的和最大的非空连续子数组。我们称这样的连续子数组为最大子数组(maximum subarray)

什么是分治策略?

1、分解(Divide) 步骤将问题划分为一些小问题,子问题的形式与原问题一样,只是规模更小
2、解决(Conquer) 步骤递归地求解出子问题,如果子问题的规模足够小,则停止递归,直接求解
3、合并(Combine) 步骤将子问题的解组合成原问题的解

对最大子数组使用分治策略

1、分解 low表示数组最小下标,mid表示数组中间下标,high表示数组最大下标。考虑数组A[low,…,mid]和A[mid+1,…high]。A[low,…,high]的任何连续子数组A[i,…,j]所处的位置有三种可能:

(1)完全的处在左侧的子数组A[low,…,mid]内。

(2)完全的处在右侧的子数组A[mid+1,…high]内。

(3)跨越了中点mid,即low<=i<=mid, mid+1<=j<=high

2、求解 :对于(1)和(2)中的两个情况,这两个子问题仍然是最大子数组问题,也即是说与原问题相同的规模较小的子问题。继续分解,知道出现情况(3),最终解决。因此下面的重点放在第(3)个情况,寻找跨越中点的最大子数组,最后在这三种情况中选择和最大的,既是问题的解。通过伪代码

对于(3)中的情况,分析可知任何跨越了中点的子数组都由两个子数组A[i,…,mid]和A[mid+1,…j]组成,找出这一数组的过程由伪代码 FIND-MAX-CROSSING-SUBARRAY(A,low,mid,high) 给出。
3、合并 :将三种情况合并,便是最终最大子数组问题的解决方法最后给出

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+A[j]
  if(sum>right-sum){
  right-sum = sum
  max-right = j
  }
}
return (max-left,max-right,left-sum + right-sum)
FIND-MAXIMUM-SUBARRAY(A,low,high)
if(high == low){
     return (low,high,A[low])
}
else mid=[(low+high)/2]
    (left-low,left-high,left-sum) = FIND-MAXIMUM-SUBARRAY(A,low,mid)
    (right-low,right-high,right-sum) = FIND-MAXIMUM-SUBARRAY(A,mid+1,high)
    (cross-low,cross-high,cross-sum) = FIND-MAX-CROSSING-SUBARRAY(A,low,mid,high)
   if (left-sum>=right and left-sum>=cross-sum)
      return (left-low,left-high,left-sum)
   elseif(right-sum>=left-sum and right-sum>=cross-sum)
    return (right-low,right-high,right-sum)
   else return (cross-low,cross-high,cross-sum)

你可能感兴趣的:(算法,算法)