1. 程式人生 > >求整數序列的子序列和的最大值

求整數序列的子序列和的最大值

一.常規思路

int sum1(int a[], int n)
{
	int i, j;
	int  maxSum = 0,curSum;
	for (i = 0; i < n; i++)
	{
		curSum = 0;//curSum表示從i開始的某子序列的和
		for (j = i; j < n; j++)
		{
			//累加從區間[i,j]內的整數和到cunSum中
			//從i開始的序列長度依次為1、2、……、n-i
			curSum += a[j];
			if (curSum > maxSum)
				maxSum = curSum;
		}
	}
	return maxSum;
}
時間複雜度  T(n)=O(n^2);

二.優化方案一

設區間[i,k]為符合條件的子序列(j<k<n), 因為a[i]+…+a[j]<0, i ≤j < k,則:a[i]+…+a[k]<a[j+1]+…+a[k],產生矛盾,表示區間[i,k]不是符合條件的子序列,同時表示i作為起點的區間[i,i]、 [i,i+1]… [i,j-1]都處理過了,下一步就是考慮i+1作為起點 。

int sum2(int a[],int n)
{
	int i, j;
    int  maxSum = 0,curSum;
    for (i = 0; i < n; i++)
  {
	    curSum = 0;
	    for (j = i; j < n; j++)
	   {
		  curSum += a[j];
		  if (curSum > maxSum)
			maxSum = curSum;
		  else if (curSum < 0)
			  break;//退出內層迴圈,考慮i+1作為起點
	   }
   }
	return maxSu
}
時間複雜度 T(n)=O(n^2);

三.進一步優化

思考是否需要考慮區間[i+1,j]中的位置m作為起點? 按演算法步驟:當考慮以i作為子序列起點時,一旦: a[i]+…+a[j]<0, (j>i),按處理過程有: 因為:a[i]+…+a[j-1] ≥ 0 所以:a[i]+…+a[m-1] ≥ 0 (i<m ≤j) ai , ai+1,…am-1,am,… aj-1, aj,…ak … an-1 如果區間[m,k]是符合條件的子區間,因為: a[i]+…+a[m-1] ≥ 0, (i<m ≤j) 則區間[i,k]中的數字之和具有更大值,產生矛盾,即不需要再考慮m作為起點的情況,這樣新的起點就可以一步跳到j+1,即i=j+1。

int sum3(int a[], int n)
{
	int i = 0, begin = -1, end = -1, maxSum = 0,curSum;
	curSum = 0;
	for (j = i; j < n; j++)
	{
		curSum += a[j];
		if (curSum > maxSum)
		{
			begin = i, end = j;
			maxSum = curSum;
		}
		else if (curSum < 0)
		{
			i = j + 1;//修改起點位置
			curSum = 0;//重新累加
		}
	}
	return maxSum;			//區間下標範圍[begin,end],
                             //[-1,-1]表示無正數
}
時間複雜度  T(n)=O(n)