問題描述: 乙個n個整數的陣列(a[0] ... a[n-1]), 求這個陣列的子陣列的最大和。
舉例:陣列:a = [1, -2, 3, 5, -3, 2] 返回: 8
解法一: 窮舉法
窮舉出所有的子陣列,分別求和,最後選出最大值
n個元素的組合有n*(n-1)種,對每種組合求和需要c次,其中c為該組合元素數
因而該演算法複雜度為o(n2)*o(n) = o(n3)
假設m[i, j]表示子陣列(a[i]... a[j]), 則該子陣列的和等於m[i, j-1] + a[j],所以只要
知道m[i, j-1],就可以一次計算出m[i, j] 的值
所以可以改進演算法, 通過避免重複計算子陣列之和來降低複雜度,改進後t(n) = o(n2)
python實現:
def submax_force(arr):
m = {}
maxnum = 0
for i inrange(len(arr)):
m[(i,i-1)]= 0
for j inrange(i, len(arr)):
m[(i,j)] = m[(i,j-1)] + arr[j]
if m[(i, j)] > maxnum:
maxnum = m[(i, j)]
return maxnum
解法二: 分治法
把陣列分為a[0]...a[n/2 - 1]和a[n/2]...a[n-1]兩部分,分別遞迴求出其最大子段和
則a[0]...a[n-1]最大子段和可能來自與以下三個子陣列之一:
1. (a[0]...a[n/2 - 1])
2. (a[n/2]...a[n-1)
3. (a[i]...a[j]) 其中i,j 跨越左右兩個子陣列
其中1,2 可以分別遞迴求解, 而3需要單獨求解
對於3 可以分別求解以a[n/2]結尾的最大子段和以a[n/2+1]為首的最大子段,然後
兩者相加即可。
該解法演算法複雜度o(n*log2n)
python實現:
def submax_divide(arr):
if len(arr)== 1:
returnarr[0]
sum1 =submax_divide(arr[0:len(arr)/2])
sum2 =submax_divide(arr[len(arr)/2: len(arr)])
sum31 =arr[len(arr)/2-1]
sum32 =arr[len(arr)/2]
tmp = 0
for i inrange(len(arr)/2)[::-1]:
tmp +=arr[i]
if tmp> sum31:
sum31= tmp
tmp = 0
for i inrange(len(arr)/2, len(arr)):
tmp +=arr[i]
if tmp> sum32:
sum32= tmp
sum3 =sum31+sum32
returnmax(max(sum1,sum2),sum3)
解法三: 動態規劃
動態規劃的兩個關鍵因素是「最優子結構」和「重疊子問題」
「最優子結構」指的是乙個問題的最優解包含子問題的乙個最優解
對於本例,考慮a[i]...a[j]的擁有最大和的子段必定是以下三種情況之一:
1.該子段僅包含a[i]
2.該子段包含且不僅a[i], 則該子段中除去a[i]的部分必然是a[i+1]...a[j]的以a[i+1]為首的擁有最大和的子段
3.該子段不包含a[i],則該子段必然是a[i+1]...a[j]的擁有最大和的子段
以上描述表明該問題擁有最優子結構,且該問題包含兩種子問題:
以a[i]為首的最大和子段,記為start[i]
a[i]...a[j]的最大和子段,記為m[i, j]
該演算法複雜度為o(n),使用了兩個陣列儲存中間值
python實現:
def submax_dp(arr):
start = {}
m = {}
m[len(arr)-1]= start[len(arr)-1] = arr[len(arr)-1]
for i inrange(len(arr)-1)[::-1]:
start[i]= max(arr[i],start[i+1] + arr[i])
m[i] =max(start[i], m[i+1])
return m[0]
空間優化:
由於start[i],m[i]僅依賴於陣列的後乙個值start[i+1],m[i+1],且陣列從後向前遍歷,所以可以把陣列改為中間值儲存
def submax_dp_lesp(arr):
m= start = arr[len(arr)-1]
for i in range(len(arr)-1)[::-1]:
start = max(arr[i],start + arr[i])
m = max(start, m)
print 'i =',i,'start =',start,'m =',m
return m
程式設計之美:
一下演算法表明了此問題的乙個有趣的解法,即從一段向另一端遍歷陣列,並累計和,若和為負值,則丟棄所有的元素,並從頭開始計算,直到最後乙個大於零的元素為止
def submax_beauty(arr):
start = arr[len(arr)-1]
max = 0
for i in range(len(arr)-1)[::-1]:
if start < 0:
start = 0
start += arr[i]
if start > max:
max = start
return max
最長子序列的問題求解
給你一組資料 比如1 7 4 5 6 8 9 7個資料 求出這一組資料中的最長公升序子串行的長度 為了這個問題糾結了很久,由於自己沒有學習什麼動態規劃 所以看了別人的說法也是沒法完全明白。為了簡化問題,只求長度 換個思路 假設我們先定下來最長的子串行的末端,比如說是1 那麼初始的原則就是只有乙個1,...
最長子序列問題
引子 洛谷p1020,飛彈攔截 問題描述 某國為了防禦敵國的飛彈襲擊,發展出一種飛彈攔截系統。但是這種飛彈攔截系統有乙個缺陷 雖然它的第一發炮彈能夠到達任意的高度,但是以後每一發炮彈都不能高於前一發的高度。某天,雷達捕捉到敵國的飛彈來襲。由於該系統還在試用階段,所以只有一套系統,因此有可能不能攔截所...
最長子段和 最大子矩陣
最長欄位和 陣列a 0.n 求出max a i.j 的和 用dp的思想做 dp i 表示從a 0 到a i 的最長子段和,並且肯定包含a i 則原問題轉換成求max dp dp i max dp i 1 a i a i 故若dp i 1 0,則dp i dp i 1 a i 若dp i 1 0,則d...