如果我必须删除子数组中的最大元素,如何找到子数组的最大和
Posted
技术标签:
【中文标题】如果我必须删除子数组中的最大元素,如何找到子数组的最大和【英文标题】:How do I find the maximum sum of subarray if i have to delete the largest element in the subarray 【发布时间】:2021-07-30 22:03:23 【问题描述】:def maxsub(a,N):
max_so_far = a[0]
curr_max = a[0]
for i in range(1,N):
curr_max = max(a[i], curr_max + a[i])
max_so_far = max(max_so_far,curr_max)
return max_so_far
N = int(input())
arr = [int(input()) for _ in range(N)]
if all(x > 0 for x in arr) == True:
print(sum(arr) - max(arr))
else:
print(maxsub(arr,N))
此代码有助于找到任何子数组的最大总和,但如果我必须删除其中的最大元素,我需要找到子数组的最大总和。
例如 如果我们在一个数组中有 7 个元素作为 [0,-11,5,5,-10,0,50] '如果我们必须删除其最大元素的子数组的最大和'将是5 对于 5 个元素 [-2,10,-2,10,6],答案将是 14 我要在这里做什么?
【问题讨论】:
看起来像一个竞争问题——你能链接到源吗?还有多快是可以接受的? 【参考方案1】:另一种方法可能是:
def maxsub(a,N):
bestSumsWithoutMax=sys.float_info.min
bestSum=0
for i in range(len(a)-1):
LastInd = min(len(a)+1,i+N+1)
for j in range(i+2,LastInd):
subA = a[i:j]
subSum =sum(subA)
subSumWM =subSum-max(subA)
if(bestSumsWithoutMax<subSumWM):
bestSumsWithoutMax=subSumWM
bestSum = subSum
return bestSumsWithoutMax, bestSum
sumsWithoutMax, associatedSum= maxsub(a,N)
print("%f %f" % (associatedSum, sumsWithoutMax))
请注意,如果您正在处理大型数组,该算法的性能可能与更明确的索引产生的性能不同。
上面的代码可以浓缩为:
def maxsub2(a,N):
bestSumWMAndIndex = max([(sum(a[i:j])- max(a[i:j]),i,j) for i in range(len(a)-1) for j in range(i+2,min(len(a)+1,i+N+1))])
return bestSumWMAndIndex[0], sum(a[bestSumWMAndIndex[1]:bestSumWMAndIndex[2]])
sumsWithoutMax, associatedSum= maxsub2(a,N)
print("%f %f" % (associatedSum, sumsWithoutMax))
编辑-----------------------------------
如果性能是关键,首先考虑用另一种语言进行编程。如果一定要坚持 Python,可以试试:
def maxsub3(a,N):
bestSumsWithoutMax=sys.float_info.min
bestSum=0
for i in range(len(a)-1):
LastInd = min(len(a),i+N)
subAini = a[i:i+2]
subSum =sum(subAini)
maxA = max(subAini)
subSumWM =subSum-maxA
if(bestSumsWithoutMax<subSumWM):
bestSumsWithoutMax=subSumWM
bestSum = subSum
for j in range(i+2,LastInd):
A = a[j]
subSum+=A
if(A>maxA):
subSumWM+=maxA
maxA=A
else:
subSumWM+=A
if(bestSumsWithoutMax<subSumWM):
bestSumsWithoutMax=subSumWM
bestSum = subSum
return bestSumsWithoutMax, bestSum
sumsWithoutMax, bestSum= maxsub(b,N)
print("%f %f" % (bestSum, sumsWithoutMax))
【讨论】:
什么是 N,为什么需要它? N 是子数组的最大大小。我不知道为什么需要它,但在问题中使用了它,所以我只是保留了这个要求。maxsub3([-10, 7, -4, 1, 5], 5)
似乎返回了(1, 8)
。我认为正确的结果是(2, 9)
。
对不起,你是对的。它必须是for j in range(i+2,LastInd):
。我正在纠正我的答案【参考方案2】:
修改 maxSub() 函数以返回最大子数组的开始和结束索引。
然后取该子数组的 max(),并从子数组的最大值中减去它
这里有一些代码。 max_finder()
返回最大总和、开始、结束索引。我按照Kadane's Algorithm
描述的here 实现了它
def max_finder(a):
cur_max, cur_start, cur_end = a[0], 0, 0
max_so_far, start_so_far, end_so_far = a[0], 0, 0
for i in range(1, len(a)):
if a[i] > cur_max+a[i]:
cur_max, cur_start, cur_end = a[i], i, i
else:
cur_max, cur_end = cur_max + a[i], i
if (cur_max - max(a[cur_start: cur_end+1])) > (max_so_far - max(a[start_so_far: end_so_far+1])):
max_so_far, start_so_far, end_so_far = cur_max, cur_start, cur_end
return max_so_far, start_so_far, end_so_far
然后
max_sum, start, end = max_finder(a)
max_val = max(a[start: end+1])
print(max_sum - max_val)
【讨论】:
这在[5, -100, 1, 1]
这样的实例上失败,因为它被大 5 “引诱”,然后消失了。
是的,在我看来是正确的,我知道@j_random_hacker 在说什么。需要详细说明吗?
抱歉,请改用[1, 1, -100, 5]
。 (您的 max_finder()
本身有一个错误:max_finder([5, -100, 1, 1])
应该是 (5, 0, 0)
但它错误地返回 (2, 2, 3)
。我给出的示例输入都有总和为 5 的子数组。)
我很抱歉@j_random_hacker,这在您的第一次输入本身上是不正确的,我没有注意到。我将相应地编辑该功能。谢谢。
没问题,但更大的问题是,既然max_finder()
正确找到了最大和间隔,both 我的示例输入在正确时给出最终答案 0答案是 1。【参考方案3】:
这是一个重复出现,对于随机数据来说似乎相当快,但对于大部分排序的数据来说速度较慢)。对于 3000 个元素,10-20 times faster 似乎比 Amo Robb 的 maxsub3 函数(对于随机的、未排序的数据)。 repl 还包括针对蛮力的准确性测试。重复是天真的 - 一些向后运行可能会根据max_subarray
阈值查找最佳解决方案。
让f(i, is_max, subarray_max)
表示以i
th 元素结尾的最大和,
其中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://***.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
【讨论】:
以上是关于如果我必须删除子数组中的最大元素,如何找到子数组的最大和的主要内容,如果未能解决你的问题,请参考以下文章