问题描述:输入一个具有n个元素的数组x,输出该数组中任何连续子数组中的最大和(为使问题定义更加完整,规定当所有元素均为负数时,总和最大的子数组是0)。
该问题在算法导论和编程珠玑中都出现过,算法导论中给出的事采用分治策略,用递归法解决的:
- 初始问题是要处理大小为n的数组,所以将它划分为两个大小近似相等的子数组,分别称为a和b。
- 然后递归的找出a、b中元素总和最大的子数组,分别称为Max(a)和Max(b).
但是,这还不是最后的结果,因为最大的子数组不一定在a和b之中,还有可能是由a的最大子数组和b的最大子数组组成的,称这部分最大子数组为Max(c)。
代码如下:
int max_array(int a[], int first, int last)
{
if(first > last)//0个元素是为0
return 0;
if(first == last)//1个元素时,取较大的一个
return max(0, a[first]);
int mid = (first + last) / 2;
int left_max = 0, sum = 0;
for(int i = mid; i >= 1; i--)//找到左半部分的最大子数组
{
sum += a[i];
left_max = max(left_max, sum);
}
int right_max = 0, sum = 0;
for(int i = mid + 1; i <= last; i++)//找到右半部分的最大子数组
{
sum += a[i];
right_max = max(right_max, sum);
}
return
max(right_max+lef_tmax,max_array(a,first,mid),max_array(a, mid+1,last));
}
/*两个max()函数如下*/
int max(int a, int b)
{
return a > b ? a : b;
}
int max(int a, int b, int c)
{
return max(a, b) > c ? max(a, b) : c;
}
除此之外,编程珠玑中还给出了一个时间复杂度为O(n)的扫描算法(线性算法):
从数组的最左端开始扫描,一直到最右端为止,记下所遇到的最大和子数组。最大和初始化为0,前i个元素中,最大和子数组要么在前i-1个元素中(存在maxsofar),要么在结束位置i(存在maxendinghere)。
int max_array(int a[])
{
int len = sizeof(a) / sizeof(int);
int maxsofar = 0, maxendinghere = 0;
for(int i = 0; i < len; i++)
{
maxendinghere = max(maxendinghere + a[i], 0);
maxsofar = max(maxsofar, maxendinghere);
}
}
在循环中的第一个赋值语句之前,maxendinghere是结束位置为i-1的最大字数组的和;赋值语句将其修改为结束位置为i的最大子数组的和。若加上a[i]后仍为正,则使maxendinghere增大a[i];若加上a[i]后为负,则将maxendinghere重置为0。