这是一个重复出现,对于随机数据来说似乎相当快,但对于大部分排序的数据来说速度较慢)。对于 3000 个元素,10-20 times faster 似乎比 Amo Robb 的 maxsub3 函数(对于随机的、未排序的数据)。 repl 还包括针对蛮力的准确性测试。重复是天真的 - 一些向后运行可能会根据max_subarray 阈值查找最佳解决方案。
让f(i, is_max, subarray_max) 表示以ith 元素结尾的最大和,
其中is_max 表示元素是否为最大值,subarray_max 是
子数组的最大值。那么:
# max isn't used if the element
# ending the subarray is fixed
# as the maximum.
def f(A, i, is_max, subarray_max, memo, ps, pfxs):
key = str((i, is_max, subarray_max))
if key in memo:
return memo[key]
if is_max:
if i == 0 or A[i-1] > A[i]:
return 0
result = f(A, i - 1, False, A[i], memo, ps, pfxs)
memo[key] = result
return result
# not is_max
if i == 0:
if A[i] > subarray_max:
return 0
return max(0, A[i])
# If max is not defined,
# we MUST include all previous
# elements until the previous equal or
# higher element. If there is no
# previous equal or higher element,
# return -Infinity because a subarray
# ending at A[i] cannot correspond
# with false is_max.
if subarray_max == None:
prev = ps[i]
if prev == -1:
return -float('inf')
best = -float('inf')
temp = ps[i]
while ps[temp] != -1:
candidate = pfxs[i] - pfxs[temp] + f(A, temp, True, None, memo, ps, pfxs)
if candidate > best:
best = candidate
# The prev equal or higher could still
# be smaller to another.
candidate = pfxs[i] - pfxs[temp] + f(A, temp, False, None, memo, ps, pfxs)
if candidate > best:
best = candidate
temp = ps[temp]
candidate = pfxs[i] - pfxs[temp] + f(A, temp, True, None, memo, ps, pfxs)
if candidate > best:
best = candidate
memo[key] = best
return best
# If max is defined, the previous
# equal or higher could be higher
# than max, in which case we need
# not include all elements in between.
if A[i] > subarray_max:
return 0
result = max(0, A[i] + f(A, i - 1, False, subarray_max, memo, ps, pfxs))
memo[key] = result
return result
def g(A):
memo = {}
best = -float('inf')
ps = find_prev_greater_elements(A)
pfxs = [A[0]] + [None] * len(A)
for i in range(1, len(A)):
pfxs[i] = A[i] + pfxs[i-1]
for i in range(len(A)):
best = max(best, f(A, i, True, None, memo, ps, pfxs))
if i > 0:
best = max(best, f(A, i, False, None, memo, ps, pfxs))
return best
# Adapted from https://stackoverflow.com/a/9495815/2034787
def find_prev_greater_elements(xs):
ys=[-1 for x in xs]
stack=[]
for i in range(len(xs)-1, -1, -1):
while len(stack)>0 and xs[i] >= xs[stack[-1]]:
ys[stack.pop()]=i
stack.append(i)
return ys