问题提出:如果知道股票的涨跌情况,如何选择在哪一天买进,哪一天卖出?
求解方法:
一、暴力求解
算出每两天的差值,这种差值一共存在n(n-1)/2个。而处理每对日期所花费的时间至少也是常量。所以这种方法的时间复杂度为Ω(n^2)。
二、问题变化——分治策略
把后一天相对前一天的涨跌情况列为数组,寻找和最大的非空连续子数组,即最大子数组。虽然看上去需要(n-1)(n-2)/2种情况,但终归是有了约束,可以利用约束来做一些事情。
考虑分治策略,把数组从中间分开,分为两个子数组,那么最大子数组出现的情况,只有三种:
1.完全包含在左边的数组中
2.完全包含在右边的数组中
3.跨越了中间值
对于1,2两种情况,就是利用分治策略的时机了。至于第三种情况,因为包含了中间值,所以只需要线性时间就可以找到。
Find-MAX-CROSSING-SUBARRAY(A,low,mid,high)
left-sum = 无穷小
sum = 0
for i = mid downto low
sum = sum+A[i]
if sum > lef-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
(lef-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)
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)
T(n) = 2T(n/2)+Θ(n)
所以T(n) = Θ(nlgn)