最長子段問題求解

2021-06-05 17:45:29 字數 3025 閱讀 6058

問題描述: 乙個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...