最大字段和求解方法

問題描述:給定n個整數(可能有負數)組成的序列a1,a2,...,an,求該序列的最大子段和。如果所有整數都是負數,那麼定義其最大子段和爲0

方法一:暴力雙重循環破解法

 

方法二:遞歸分治

在數組的 center = (right-left)/2+left 位置處分開。形成兩個子數組。

那麼,最大子段和 可能出現在三個位置:

          a,可能出現在【左子數組】

          b,可能出現在【右子數組】 

          c,可能出現在【過center的 中間某部分元素組成的子數組】。

下面考慮 三種情況的計算方法:

第一種情況: 計算 left 到 center 的最大和,記作 leftSum

第二種情況: 計算從 center+1 到 right的最大和,記作 rightSum

第三種情況: 跨邊界的和。 ;以center爲中心分別向兩邊計算和。

      a.從 center出發,每次向左邊擴張一步,並且記錄當前的值S1,如果當前的和比上次的和大,就更新S1,一直向左擴張到 位置  Left。 

      b.從 center+1出發,每次擴張一步,計算當前的和 爲S2,如果當前的值比上次的和 大,那麼,就更新S2的值,一直向右擴張到位置Right。

      c.計算過center的連續值的和,S1+S2的值 Sum。 這個就是跨邊界的和。

 上面三種情況考慮計算完成後,最後一步就是,比較三個值中的最大值,取最大值就可以了。

代碼部分:

int MaxSubSum(int a[], int left, int right) {
	if (right == left)                //遞歸結束的標誌
		return a[left]>0?a[left]:0;
	int center = (left + right) / 2;
	int leftsum = MaxSubSum(a, left, center);    //左子段的最大值
	int rightsum = MaxSubSum(a, center+1, right);    //右子段的最大值
	int s1 = 0, s2 = 0, cur_t = 0;
	for (int i = center; i >= 0; i--) {            //center到left的連續的最大值
		cur_t += a[i];
		if (cur_t > s1)
			s1 = cur_t;
	}
	cur_t = 0;
	for (int i = center+1; i <= right; i++) {        //center到right的連續的最大值
		cur_t += a[i];
		if (cur_t > s2)
			s2 = cur_t;
	}
	int sum = s1 + s2;                                //sum是過center的連續的最大值
	return leftsum > rightsum ? (leftsum > sum ? leftsum : sum) : (rightsum > sum ? rightsum : sum);                //比較三者的大小,返回最大的那一個
}

 

 

方法三:動態規劃

代碼部分:

int MaxSubArray(int a[], int n) {
	int i, b = 0, sum = 0;
	for (i = 0; i < n; i++) {
		if (b > 0)				//b看作b[i-1],如果b是負數那肯定沒有a[i]大 b=max(b[i-1]+a[i], a[i])
			b += a[i];
		else
			b = a[i];

		if (b > sum)			//取得b的極值
			sum = b;
	}
	return sum;
}

 

參考文獻:

https://www.cnblogs.com/TIMHY/p/8284989.html

https://www.cnblogs.com/lixing-nlp/p/7629403.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章