寻找最大子数组问题:
给定数组A:寻找A中的和最大的非空连续子数组。我们称这样的连续子数组为最大子数组(maximum subarray)
1、暴力求解:两个循环,时间复杂度为O(n^2)
2、用分治策略的求解方法:
假定我们要寻找子数组A[low...high]的最大子数组。使用分治技术意味着我们要将子数组划分为两个规模尽量相等的子数组。也就是,找到子数组的中央位置,比如mid,然后考虑求解两个子数组A[low...mid]和A[mid+1...high]。A[low...high]的任何连续子数组A[i ...j]所处的位置必然是一下三种情况之一:
1.完全位于子数组A[low...mid]中,因此low<=i<=j<=mid
2.完全位于子数组A[mid+1...high]中,因此mid<i<=j<=high
3.跨越了中点,因此low<=i<=mid<j<=high
我们可以递归地求解A[low...mid]和A[mid+1...high]的最大子数组。剩下的全部工作就是寻找跨越中点的最大子数组,然后在三种情况中选取最大者。
时间复杂度为O(n)。
分治法python求解如下:
def max_cross_subarray(low, mid, high, array):
max_low, max_high = low, high
left_sum = float("-inf")
sum = 0
for i in range(mid, low-1, -1):
sum += array[i]
if sum > left_sum:
left_sum = sum
max_low = i
right_sum = float("-inf")
sum = 0
for j in range(mid+1, high + 1):
sum += array[j]
if sum > right_sum:
right_sum = sum
max_high = j
max_sum = left_sum + right_sum
return(max_low, max_high, max_sum)
def max_subarray(array, low, high):
mid = (low + high)//2
if low == high:
return(low, high, array[low])
else:
#完全位于子数组A[low...mid]中
(left_low, left_high, left_max) = max_subarray(array, low, mid)
#完全位于子数组A[mid+1...high]中
(right_low, right_high, right_max) = max_subarray(array, mid+1, high)
#跨越了中点
(mid_low, mid_high, mid_max) = max_cross_subarray(low, mid, high, array)
#比较三种情况的最大值,求整体最大值
if left_max > right_max and left_max > mid_max:
max_sum = left_max
sub_low = left_low
sub_high = left_high
elif right_max > left_max and right_max > mid_max:
max_sum = right_max
sub_low = right_low
sub_high = left_high
else:
max_sum = mid_max
sub_low = mid_low
sub_high = mid_high
return(sub_low, sub_high, max_sum)
#test
if __name__ == '__main__':
array = [13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7,]
max = max_subarray(array, 0, len(array)-1)
print(max)
#output
#(7,10,43)