购买股票的时候,我们都希望在较低价的时候买入,在较高价的时候卖出,来最大化收益。
股票的问题可以转化为最大子数组的问题,其中数组中的每个数字为相邻两天价格的差。
最大子数组需要找出连续的和最大的子数组。
最大子数组问题的解决可以通过分治的算法。找到数组的中间的数的位置,然后将数组划分为两个子数组,
下标范围分别是 0-p 和 p+1-n,n表示数组大小,分别递归求两个子数组的最大子数组,另外求跨越中间位置的最大子数组。
比较三个最大子数组中的最大值,作为最终的返回值。可以通过求解递归式(参考《算法导论》)可以得出该算法的时间复杂度为o(nlogn)。
代码
#coding : utf-8
def find_max_crossing_subarray(arr,low,mid,high):
max_left_sum = float("-inf")
max_left = mid
sum = 0
for i in range(mid, low-1, -1):
sum += arr[i]
if sum > max_left_sum:
max_left_sum = sum
max_left = i
max_right = mid
max_right_sum = float("-inf")
sum = 0
for i in range(mid+1, high+1):
sum += arr[i]
if sum > max_right_sum:
max_right_sum = sum
max_right = i
return (max_left,max_right,max_left_sum+max_right_sum)
def find_max_subarray(arr,low,high):
if low == high:
return (low,high,arr[low]) # base case: only one element
else:
mid = (low+high)/2
(left_low,left_high,left_sum) = find_max_subarray(arr,low,mid)
(right_low,right_high,right_sum) = find_max_subarray(arr,mid+1,high)
(cross_low,cross_high,cross_sum) = find_max_crossing_subarray(arr,low,mid,high)
if max(left_sum,right_sum,cross_sum) == left_sum:
return (left_low,left_high,left_sum)
elif max(left_sum,right_sum,cross_sum) == right_sum:
return (right_low,right_high,right_sum)
else:
return (cross_low,cross_high,cross_sum)
def show_max_subarray(arr,low,high):
print "[", ", ".join([str(x) for x in arr[low:high+1]]), "]"
if __name__ == "__main__":
arr = [13, -3, -25 , 20, -3 , -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7]
low,high,sum_v = find_max_subarray(arr,0,len(arr)-1)
print low,high,sum_v
show_max_subarray(arr,low,high)