题目:输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组的和的最大值。要求时间复杂度为O(n)。比如输入a[]={31,-41,59,26,-53,58,97,-93,-23,84},那么程序的输出为a[2…6]的和,即187。
《编程珠玑》给出了一个时间复杂度为O(n)的扫描算法。代码非常简练,但得稍微思考一下才能明白。
首先我们必须找到最大的子数组的起始点,从a[0]开始扫描,并且逐一累加,累加和存储到max_ending_here变量。当累加到i,即a[0]+a[1]+…a[i]的和小于0时,我们认定最大子数组绝对不包括a[0]~a[i],就可以更新最大子数组的起始位置begin=i+1,并将max_ending_here清0。所以说max_ending_here始终存储的是累加和大于0的子数组累加和。这时还需要另外一个变量max_sofar存储当前的最大子数组累加和。每扫描一个数据就将max_ending_here和max_sofar进行一次比较,保证max_sofar始终存储目前最大的子数组累加和。代码如下:
#include "stdafx.h"
#include "stdio.h"
#include <iostream>
using namespace std;
int max_subarray(const int a[],int n)
{
int max_ending_here=0;
int max_sofar=0;
int begin=0;
int end=0;
int i=0;
for(i=0;i<n;i++)
{
if(max_ending_here+a[i]>0)
max_ending_here=max_ending_here+a[i];
else
{
begin=i+1; //注意begin更新为i+1而不是i
max_ending_here=0;
}
cout<<"max_ending_here: "<<max_ending_here<<endl;
if(max_ending_here>max_sofar)
{
max_sofar=max_ending_here;
end=i;
}
cout<<"max_sofar: "<<max_sofar<<endl;
}
cout<<"max subarray begin="<<begin<<" "<<"end="<<end<<endl;
return max_sofar;
}
int _tmain(int argc, _TCHAR* argv[])
{
int sum;
int a[]={31,-41,59,26,-53,58,97,-93,-23,84};
sum= max_subarray(a,10);
cout<<sum<<endl;
getchar();
}