在书中"编程访谈的元素",我遇到了,返回最大总和的子阵列的问题。我尝试了他们的解决方案,我认为我们不需要跟踪最小总和来获得最大总和的数组:
我写了另一个版本的maximumSumMine,我删除了minSum,它工作正常,评论中的输出
跟踪minSum的目的是什么,我们真的需要吗?
#include <stdio.h>
#include <limits.h>
typedef struct range {
int start;
int end;
int maxSum;
} range;
void print(int *a, int start, int end) {
for (int i = start; i <= end; i++) {
printf("%d ", a[i]);
}
printf("\n");
}
// Book's code as it is
range maximumSum(int *a, int n) {
range r;
r.start = 0; r.end = 0;
int minSum = 0, sum = 0, minIndex = -1, maxSum = INT_MIN;
for (int i = 0; i < n; i++) {
sum += a[i];
if (sum < minSum) {
minSum = sum;
minIndex = i;
}
if (sum - minSum > maxSum) {
maxSum = sum - minSum;
r.start = minIndex + 1;
r.end = i + 1;
}
}
return r;
}
range maximumSumMine(int *a, int n) {
range r;
r.start = 0; r.end = 0;
int sum = 0, minIndex = -1, maxSum = INT_MIN;
for (int i = 0; i < n; i++) {
sum += a[i];
if (sum < 0) {
sum = 0;
minIndex = i + 1;
}
if (sum > maxSum) {
maxSum = sum;
r.start = minIndex;
r.end = i;
}
}
return r;
}
void unitTests() {
// Example 1
int a[5] = {-2, 5, 1, -1, 4};
range r = maximumSum(a, 5);
print(a, r.start, r.end); // output 5 1 -1 4 0
// Example 2
int b[5] = {2, -5, 5, -1, 3};
r = maximumSum(b, 5);
print(b, r.start, r.end); // 5 -1 3 1
// Example 1
r = maximumSumMine(a, 5);
print(a, r.start, r.end); // output 5 1 -1 4
// Example 2
r = maximumSum(b, 5);
print(b, r.start, r.end); // 5 -1 3 1
}
int main() {
unitTests();
return 0;
}
答案 0 :(得分:4)
您需要最小总和,因为算法涉及计算前缀和:
sums[i] = a[0] + a[1] + ... + a[i]
因此,对于每个i
,您可以获得的结果为a[i]
的最大金额为sums[i] - min(sums[j < i])
。
书籍代码在没有实际使用数组的情况下实现了这一点,因为您可以简单地跟踪最小值和当前前缀总和。
如果你只在你所做的条件下取最大的前缀和,它将不适用于负的最大总和:如果最大总和为负,你将始终输出0,因为你将前缀总和设置为0当它变为负面时。
有时,忽略负的最大总和可能完全没问题,有时则不然。我已经看到两个版本作为编程任务/问题。
示例:
a = {-1, -2, -3}
book output = -1
your output = 0