一、題目
給定乙個整數陣列 nums ,找到乙個具有最大和的連續子陣列(子陣列最少包含乙個元素),返回其最大和。
示例:輸入: [-2,1,-3,4,-1,2,1,-5,4],
輸出: 6
解釋: 連續子陣列 [4,-1,2,1] 的和最大,為 6。
二、思路-分治法
分治法是將整個陣列切分成幾個小組,然後每個小組再切分成幾個更小的小組,一直到不能繼續切分也就是只剩乙個數字為止。每個小組會計算出最優值,匯報給上一級的小組,一級一級匯報,上級拿到下級的匯報找到最大值,得到最終的結果。和歸併排序的演算法類似,先切分,再合併結果。
這個問題中的關鍵就是如何切分這些組合才能使每個小組之間不會有重複的組合(有重複的組合意味著有重複的計算量),這個問題應該困擾了不少的同學,我在學習理解的時候也花了不少時間。
首先是切分分組方法,就這個案例中的例子來,我們有乙個陣列 [-2,1,-3,4,-1,2,1,-5,4] ,一共有 9 個元素,我們 center=(start + end) / 2 這個原則,得到中間元素的索引為 4 ,也就是 -1,拆分成三個組合:
[-2,1,-3,4,-1]以及它的子串行(在-1左邊的並且包含它的為一組)
[2,1,-5,4]以及它的子串行(在-1右邊不包含它的為一組)
任何包含-1以及它右邊元素2的序列為一組(換言之就是包含左邊序列的最右邊元素以及右邊序列最左邊元素的序列,比如 [4,-1,2,1],這樣就保證這個組合裡面的任何序列都不會和上面兩個重複)
以上的三個組合內的序列沒有任何的重複的部分,而且一起構成所有子串行的全集,計算出這個三個子集合的最大值,然後取其中的最大值,就是這個問題的答案了。
然而前兩個子組合可以用遞迴來解決,乙個函式就搞定,第三個跨中心的組合應該怎麼計算最大值呢?
答案就是先計算左邊序列裡面的包含最右邊元素的子串行的最大值,也就是從左邊序列的最右邊元素向左乙個乙個累加起來,找出累加過程中每次累加的最大值,就是左邊序列的最大值。
同理找出右邊序列的最大值,就得到了右邊子串行的最大值。左右兩邊的最大值相加,就是包含這兩個元素的子串行的最大值。
在計算過程中,累加和比較的過程是關鍵操作,乙個長度為 n 的陣列在遞迴的每一層都會進行 n 次操作,分治法的遞迴層級在 logn 級別,所以整體的時間複雜度是 o(nlogn),在時間效率上不如動態規劃的 o(n) 複雜度。
分治法的思路是這樣的,其實也是分類討論。
連續子串行的最大和主要由這三部分子區間裡元素的最大和得到:
第 1 部分:子區間 [left, mid];
第 2 部分:子區間 [mid + 1, right];
第 3 部分:包含子區間[mid , mid + 1]的子區間,即 nums[mid] 與nums[mid + 1]一定會被選取。
對它們三者求最大值即可。『
三、分治法**
class
solution
(object):
defmaxsubarray
(self, nums)
:return self.maxsubarraydividewithborder(nums,0,
len(nums)-1
)def
maxsubarraydividewithborder
(self,nums, start, end)
:if start == end:
# 只有乙個元素,也就是遞迴的結束情況
return nums[start]
# 計算中間值
center =
(start + end)/2
leftmax = self. maxsubarraydividewithborder(nums, start, center)
# 計算左側子串行最大值
rightmax = self.maxsubarraydividewithborder(nums, center +
1, end)
# 計算右側子串行最大值
# 下面計算橫跨兩個子串行的最大值
# 計算包含左側子串行最後乙個元素的子串行最大值
leftcrossmax =
0# 初始化乙個值
leftcrosssum =
0for i in
range
(center, start-1,
-1):
leftcrosssum += nums[i]
leftcrossmax =
max(leftcrosssum, leftcrossmax)
# 計算包含右側子串行最後乙個元素的子串行最大值
rightcrossmax = nums[center+1]
rightcrosssum =
0for i in
range
(center +
1, end+1)
: rightcrosssum += nums[i]
rightcrossmax =
max(rightcrosssum, rightcrossmax)
# 計算跨中心的子串行的最大值
crossmax = leftcrossmax + rightcrossmax
# 比較三者,返回最大值
return
max(crossmax,
max(leftmax, rightmax)
)
四、分治法執行結果
劍指offer 面試題42 連續子陣列的最大和
輸入乙個整形陣列,陣列裡有正數也有負數。陣列中的乙個或連續多個整數組成乙個子陣列。求所有子陣列的和的最大值。要求時間複雜度為o n 例如,輸入的陣列為,和最大的子陣列為,因此輸出為該子陣列的和18。看下面的 注釋 題目 hz偶爾會拿些專業問題來忽悠那些非計算機專業的同學。今天測試組開完會後,他又發話...
劍指offer 面試題42 連續子陣列的最大和
面試題 劍指offer 題目解答 輸入乙個整形陣列,陣列裡有正數和負數。陣列中的乙個或連續多個整數陣列做成乙個子陣列。求所有子陣列的和的最大值。要求時間複雜度為o n 如 和最大的子陣列是,所以輸出和 18 首先,我們需要乙個變數來存放子陣列和的最大值。然後我們來討論一下如何來求這個最大值呢?最簡單...
劍指offer 面試題 42 連續子陣列的最大和
hz偶爾會拿些專業問題來忽悠那些非計算機專業的同學。今天測試組開完會後,他又發話了 在古老的一維模式識別中,常常需要計算連續子向量的最大和,當向量全為正數的時候,問題很好解決。但是,如果向量中包含負數,是否應該包含某個負數,並期望旁邊的正數會彌補它呢?例如 連續子向量的最大和為8 從第0個開始,到第...