最大子数组算法

题目:输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。

求所有子数组的和的最大值。要求时间复杂度为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();
	
}

点赞