最大子數組問題
問題描述
Find the contiguous subarray within an array (containing at least one number) which has the largest sum.
For example, given the array [−2,1,−3,4,−1,2,1,−5,4],
the contiguous subarray [4,−1,2,1] has the largest sum = 6.
暴力求解法:
# -*- coding:utf-8 -*-
def max_subarray(source):
sum_max = -float("inf")
array_max = []
for i in range(len(source)):
for j in range(i+1, len(source)):
sum_now = sum(list[i:j+1])
if sum_now > sum_max:
sum_max = sum_now
array_max = list[i:j+1]
return array_max
print max_subarray([13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7])
分治法:
其實就是分解成最小的子問題,求解跨越數組中點的最大子數組問題
僞代碼,摘抄自算法導論P42
FIND-MAX-CROSSING-SUBARRAY(A, low, mid, high)
left_sum = - Inf
sum = 0
for i = mid downto low
sum = sum + a[i]
if sum > left_sum
left_sum = sum
max_left = i
right_sum = - Inf
sum = 0
for j = mid + 1 to high
sum = sum + a[i]
if sum > right_sum
right_sum = sum
max_right = j
return (max_left, max_right, left_sum + right_sum)
FIND-MAX-SUBARRAY(A,low,high)
if high == low:
return (low, high, A[low])
else
mid = [(low + high) / 2] // []是取整
(left_low,left_high,left_sum) = FIND-MAX-SUBARRAY(A,low,mid)
(right_low,right_high,right_sum) = FIND-MAX-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_high
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)
def max_crossing_subarray(source, low, mid, high):
left_sum = float("-Inf")
right_sum = float("-Inf")
# 累加值初始化爲正無窮
sum_now = 0
for i in range(mid, low-1, -1):
sum_now = sum(source[mid: i-1: -1])
if sum_now > left_sum:
left_sum = sum_now
max_left = i
sum_now = 0
for j in range(mid+1, high+1):
sum_now = sum(source[mid+1:j+1])
if sum_now > right_sum:
right_sum = sum_now
max_right = j
# 找到從mid起始分別到左邊和右邊的最大子數組
return max_left, max_right, left_sum + right_sum
# 將左邊的最大子數組與右邊的最大子數組合並
def max_array(source, low, high):
if high == low:
return low, high, source[low]
else:
mid = (low+high)/2
left_low, left_high, left_sum = max_array(source, low, mid)
# 左邊的最大子數組
right_low, right_high, right_sum = max_array(source, mid+1, high)
# 右邊的最大子數組
cross_low, cross_high, cross_sum = max_crossing_subarray(source, low, mid, high)
# 跨越中點的最大子數組
if left_sum >= right_sum and left_sum >= cross_sum:
return left_low, left_high, left_sum
elif right_sum >= left_sum and right_sum >= cross_sum:
return right_low, right_high, right_sum
else:
return cross_low, cross_high, cross_sum
# 三種情況互相比較,返回最大的情況
a = [14, -2, -17, 2, 8, 9, -20, 11]
print max_array(a, 0, 7)