《算法导论》中提出的一个解题思路,从数组的左边界开始,由左至右处理,记录到目前为止已经处理过的最大子数组。若已知A[1..j]的最大子数组基于如下性质将解扩展为A[1..j+1]的最大子数组:A[1..j+1]的最大子数组要么是A[1..j]的最大子数组,要么是某个子数组A[i..j+1](1≤i≤j+1)。在已知A[1..j]的最大子数组的情况下,可以在线性时间内找出形如A[i..j+1]的最大子数组。该算法的时间复杂度为因此该算法的时间复杂度为Θ(n)
#include <stdio.h>
#include <string.h>
struct subarray {
int start;
int end;
int sum;
};
#define max(__x, __y) ((__x) > (__y) ? (__x) : (__y))
static void max_sumarray(int *a, int len, void *p)
{
struct subarray *sa = (typeof(sa))p;
int i;
int max_sum, prev, tmp;
int start, end;
if (!sa || (len <= 0)) {
fprintf(stderr, "Invalid argument.\n");
return;
}
memset(sa, 0, sizeof(*sa));
max_sum = a[0];
prev = a[0];
start = end = 0;
for (i = 1; i < len; ++i) {
prev = max(a[i], prev + a[i]); //寻找以当前位置为结尾的最大子串
if (prev < max_sum) {
/**
**如果以当前位置为结尾的最大子串是其本身,则下次扫描时以当前位置为结尾的最大子串的起始位置为本位置
**/
if (prev == a[i]) {
start = i;
}
continue;
}
max_sum = prev;
if (prev == a[i]) {
sa->start = sa->end = i;
} else {
sa->start = start;
sa->end = i;
}
}
sa->sum = max_sum;
}
int main(void)
{
int source[] = {13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7};
struct subarray sa;
max_sumarray(source, sizeof(source) / sizeof(source[0]), &sa);
printf("Max sum: %d, start: %d, end: %d.\n", sa.sum, sa.start, sa.end);
return 0;
}