一維子陣列最大和

小弟季義欽發表於2012-11-16
/*
 * MaxSumSubArray.cpp
 *
 *  Created on: 2012-6-20
 *      Author: jiyiqin
 *
 *  給定一個包含正數,負數,0的陣列,求一個連續的子陣列,使得其和最大
 */
#include <iostream>
using namespace std;

#define MIN_INT -10000
class MaxSumOfSubArray{
public:

	/**
	 * 二重迴圈查詢最大和子陣列,依次以a[i]為起點,
	 * 求解sum[i,j],更新當前最大和的值
	 * 注意陣列全是負數的情況
	 * */
	static int m1_subArray(int a[], int size)
	{
		int max_sum = MIN_INT;					//max賦值一次
		if(a == NULL || size <=0) return -1;	//輸入是否合法判斷

		for(int i=0;i<size;i++)
		{
			int sum = 0;
			for(int j=i;j<size;j++){
				sum += a[j];
				if(sum > max_sum) max_sum = sum;	//更新max
			}
		}
		cout<<"max_sum:"<<max_sum<<endl;
		return 1;
	}

	/**
	 * 線性時間完成:
	 * 記錄當前max,逐個累加
	 * 如果和sum變成負,丟棄(更新起點)。
	 * 如果sum > max,更新max。
	 * 注意陣列全部是負數的時候,"負數和"也擁有和當前最大和比較的權利
	 * */
	static int m2_subArray(int a[], int size)
	{
		int max_sum = MIN_INT;					//最大和初值為最小數字
		int sum = 0;
		if(a == NULL || size <=0) return -1;	//輸入是否合法判斷

		for(int i=0;i<size;i++)
		{
			sum += a[i];
			if(sum > max_sum) max_sum = sum;	//更新max
			if(sum <= 0) sum = 0;				//重新開始計算和
		}
		cout<<"max_sum:"<<max_sum<<endl;
		return 1;
	}

	/**
	 * 動態規劃方法:
	 * 很明顯求解最大子陣列和的問題有子結構,並且滿足“無後效性”。
	 * 即問題可以被劃分為多個階段,未來階段狀態f(i+1)的求解僅僅與
	 * 當前狀態f(i)通過狀態轉移方程得到,而與過去的歷史狀態無關。
	 * 我們設sum(i)為以a[i]結尾的最大子陣列和.
	 *
	 * 如果sum(i-1) =< 0:
	 * 		很明顯我們不應當將其簡單拋棄,因為我們還要考慮陣列a全部都是負數的情況,
	 * 		所以我們仍然將其與a[i]比較,所以sum(i) = max{sum(i-1), a[i]};
	 * 如果sum(i-1) > 0:
	 * 		因為sum(i-1)是以a[i-1]結尾的,所以很明顯sum(i) = sum(i-1)+a[i];
	 * 所以我們得到狀態轉移方程如下:
	 * sum(i) =
	 * 		sum(i-1)+a[i];			sum(i-1) > 0
	 * 		max{sum(i-1), a[i]};	sum(i-1) <= 0
	 * */
	static int m3_subArray(int a[], int size)
	{
		int *sum = new int[size];
		int max_sum = MIN_INT;
	
		if(a == NULL || size <= 0) return -1;	//判斷輸入是否合法
		for(int k=0;k<size;k++) sum[k] = 0;		//初始化sum陣列

		//順著i自底向上求解
		sum[0] = a[0];
		for(int i=1;i<size;i++)
		{
			if(sum[i-1] > 0) sum[i] = sum[i-1]+a[i];
			else sum[i] = sum[i-1]>a[i]?sum[i-1]:a[i];
			
			//更新max_sum
			if(sum[i] > max_sum) max_sum = sum[i];
		}
		
		//輸出結果
		cout<<"max_sum:"<<max_sum<<endl;
		for(int j=0;j<size;j++)
			cout<<sum[j]<<" ";
		cout<<endl;
		return 1;
	}

	static void test(){
		int a[10] = {-1,2,-5,2,-1,-13,15,-2,8,-1};
		for(int i=0;i<10;i++){
			cout<<a[i]<<" ";
		}
		cout<<endl;

		m1_subArray(a, 10);	//方法1
		m2_subArray(a, 10);	//方法2
		m3_subArray(a, 10);	//方法3
	}
};

int main(){
	MaxSumOfSubArray::test();
	return 0;
}

相關文章