最大子陣列問題,即給定乙個陣列a,找到a中和最大的非空連續子陣列。
例如:有陣列a = , 則其中的最大子陣列為a[2..3],其和為7.
最後,分析了最大子陣列問題的擴充套件問題的求解方法。
2.1.1分治概述
分治策略中,我們遞迴的求解乙個問題,在每個問題中應用如下三個步驟:
1.分解將問題劃分為一些子問題,子問題的形式與原問題一樣,只是問題規模更小。
2.解決遞迴的求解出子問題。如果子問題的規模足夠小,則停止遞迴,直接求解。
3.合併將子問題的解組合成原問題的解。
2.1.2分治求解
要尋找陣列a的最大子陣列,使用分治策略則需要將陣列a劃分為兩個規模盡量相等的子陣列。然後考慮求解兩個子陣列a[low,…,mid]和a[mid+1,…,high]。那麼,a的任何連續子陣列a[i,…,j]所處的位置必然是以下三種情況之一:
跨越中點的最大子陣列–偽**:
find-max_crossing-subarray(a, low, mid, high)
left-sum = -∞
sum = 0
for i = mid downto low
sum = sum + a[i]
ifsum > left-sum
left-sum = sum
max-left = i
right-sum = -∞
sum = 0
for j = mid+1
to high
sum = sum + a[j]
ifsum > right-sum
right-sum = sum
max-right = j
return(max-left, max-right, left-sum + right-sum)
第1-7行求出了左半部分的最大子陣列,因為必須包含mid,第3-7行的for迴圈從mid開始,遞減到low。left-sum儲存目前為止找到的最大和,sum儲存a[i,…mid]中的所有值,max-left記錄下表i。同理,第8-14行求出了右半部分的最大子陣列。
注意,如果a[low,…,high]包含n個元素,則呼叫find-max_crossing-subarray將花費θ(n)的時間.
最大子陣列的分治演算法–偽**:
find-maximun-subarray(a, low, high)
if high == low
return (low, high, a[low])
else
mid = (low + high) / 2
(left-low, left-high, left-sum) = find-maximun-subarray(a, low, mid)
(right-low, right-high, right-sum) = find-maximun-subarray(a, mid + 1, high)
(cross-low, cross-high, cross-sum) = find-max_crossing-subarray(a, low, mid, high)
return (max(left-sum, right-sum, cross-sum))
第1行測試基本情況,即子陣列只有乙個元素的情況,該測試很重要。
第4-5行遞迴求解左右子陣列中的最大子陣列,第6-7行完成合併工作。
該分治演算法的執行時間t(n) = θ(nlgn)。
當我們加上乙個正數時,和會增加;當我們加上乙個負數時,和會減少。如果當前得到的和是個負數,那麼這個和在接下來的累加中應該拋棄並重新清零,不然的話這個負數將會減少接下來的和。
基於這樣的思路,我們有**:
/* 最大子陣列 返回起始位置 */
int maxsum_subarray(int * arr, int size, int & start, int & end)
else
if(sum > maxsum)
}return maxsum;
}
該演算法的執行時間為t(n) = o(n),且空間上為o(1)。
ps:參考自
如果陣列arr[0],…,arr[n-1]首尾相鄰,也就是允許找到一段數字arr[i],…,arr[n-1],arr[0],…,a[j],使其和最大,該如何?
程式設計之美解法:這個問題的解可以分為兩種情況:
1) 解沒有跨越arr[n-1]到arr[0] (原問題)
2) 解跨越arr[n-1]到arr[0]
分析有:
陣列a = 中的最大子陣列為【1 | 3, 5, -1, 2】,即去掉了-2.
陣列b = 中的最大子陣列為【8 | 60, 3, -1, -6】, 即去掉了-10.
這兩個數都是兩個陣列中「最小」的。
所以,我們找最大子陣列的對偶問題——最小子陣列,有了最小子陣列的值,總值減去它即可得到跨界的最大子陣列(如果結果確實跨界的話)。
因此,在允許陣列跨界(首尾相鄰)時,最大子陣列的和為下面的最大值。
maxsum=
**為:
/* 如陣列首尾相鄰 */
int maxsum_endtoend(int * arr, int
size)
int maxsum_adj = -inf; /* 跨界的最大子陣列和 */
//以下求最小子陣列和
int totalsum = 0; /* 總值 */
int minsum = inf;
int tmpmin = 0;
for(int i = 0; i < size; ++i) /* 最小子陣列和 道理跟最大是一樣的 */
else
if(tmpmin < minsum)
totalsum += arr[i];
}maxsum_adj = totalsum - minsum;
return maxsum_notadj > maxsum_adj ? maxsum_notadj : maxsum_adj;
}
此時,該演算法的時間複雜度為t(n) = o(n)。 最大子陣列問題
顧名思義,最大子陣列問題是求乙個陣列array中 和最大的非空連續子陣列 這樣的連續子陣列我們叫做最大子陣列,它的應用也有 很多,比如說找出時間序列中兩個時間節點使得這兩個時間節點對應的值的落差最大,如下圖 對於這類問題,通過求原始時間序列的一階差分得到序列array,此時求得array的最大子陣列...
最大子陣列問題
include include include typedef struct num num extern void displayarray const int a,const int n 顯示陣列元素值 extern void buildarray int a,const int n 陣列元素賦...
最大子陣列問題
每週堅持搞三種演算法問題,介紹一下最大子陣列問題 演算法思路 分治策略求解,將問題不斷分為更小的問題,進而求解 問題描述 求陣列中相連著的數 相加值最大,例如 輸出最大為2 3 4 21 22 define crt secure no warnigns include include include...