vlambda博客
学习文章列表

4.1 最大子数组问题

已知某股票一段时间每日收盘价格,在只能买进卖出各一次的情况下计算最大收益。我们考察每日价格变化,第   天的价格变化定义为第   天和第   天的价格差,计算最大收益问题转化为寻找价格差数组的和最大的非空连续子数组。一般来说,只有数组同时包含正数和负数时,问题才有意义。
 递归求解,对于数组    ,记数组中间位置为   ,任一子数组   的位置有三种情况,
  • 位于子数组   
  • 位于子数组   
  • 跨越了中点 
前两种情况为原问题的更小规模,因此先找出跨越中点的最大子数组,再与前两种比较找出最大者。
寻找跨越中点的最大子数组过程接受数组   和下标   ,返回跨越中点的最大子数组的边界以及数组的和,时间复杂度为   
FIND-MAX-CROSSING-SUBARRAY(A,low,mid,high)
left_sum = -INFsum = 0for i = mid downto low    sum = sum + A[i]    if sum > left_sum       left_sum = sum       max_left = iright_sum = -INFsum = 0for j = mid+1 to high    sum = sum+A[j]    if sum > right_sum       right_sum = sum       max_right = jreturn(max_left,max_right ,left_sum+right_sum)
求解最大子数组算法会 调用自身两次并且 找跨越中点的最大子数组,时间复杂度为   
FIND-MAXIMUM-SUBARRAY(A,low,high)
if high == low     //base case  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_sum and  left_sum >= cross_sum     return (left_low,left_high,left_sum)  else if right_sum >= left_sum and       right_sum >= cross_sum     return (right_low,right_high     ,right_sum)  else return(cross_low,cross_high       ,cross_sum)
4.1-4
修改算法,允许结果为空数组

遍历数组,如果没有正数,返回空数组,和为零。
4.1-5
为本问题设计一个非递归,线性时间的算法


Kadane's algorithm
int max_so_far = a[0];int max_ending_here = a[0];
for (int i = 1; i < size; i++){ max_ending_here = Math.max(a[i], max_ending_here+a[i]); max_so_far = Math.max(max_so_far, max_ending_here);}return max_so_far;