標籤:
Problem Difinition:
Find the contiguous subarray within an array (containing at least one number) which has the largest sum.
For example, given the array [−2,1,−3,4,−1,2,1,−5,4],
the contiguous subarray [4,−1,2,1] has the largest sum = 6.
More practice:
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.
Solution:
1)動態規劃.
輸入數組為nums,用 a[i] 表示nums[0...i]這部分元素的子序列(此子序列以元素nums[i]結尾,不管它以誰開頭)能得到的最大累加和。則有遞推關係:
a[ i ] =nums[ i ]+ ( a[i-1] if a[i-1]>0 else 0)
求解過程就是迭代整個數組,求最大的a[ i ]。可以用一個數組來儲存所有的a[ i ],空間複雜度O(n)。
然而實際上不需要一個數組來存放所有的a[ i ],而用一個變數代替。
1 # @param {integer[]} nums 2 # @return {integer} 3 def maxSubArray(nums): 4 5 maxSum=-sys.maxint 6 sm=0 7 begin=0 8 end=0 9 maxBegin=010 maxEnd=011 for i, n in enumerate(nums):12 sm+=n13 if sm>maxSum:14 maxSum=sm15 maxBegin=begin16 maxEnd=end17 if sm<=0:18 begin=i+119 end=i+120 sm=021 else:22 end+=123 return nums[maxBegin: maxEnd+1]
以上演算法會求出得到最大和的完整子序列,更通用,思路也表達得比較清晰。然而題目的要求只是求出這個最大和,所以可以精簡很多:
1 # @param {integer[]} nums 2 # @return {integer} 3 def maxSubArray(nums): 4 maxSum=-sys.maxint 5 sm=0 6 for n in nums: 7 sm+=n 8 maxSum=max(maxSum, sm) 9 sm=max(sm, 0)10 return maxSum
實際上想法很簡單,逐一累加元素,一旦和不大於0,則從下一個位置開始,重新累加,並在這個過程中不斷更新最大和。
2)分治。
基本思想:
1._分。把數組切成左右兩部分,那麼給出最大累加和的子序列,要麼全在左邊,要麼全在右邊,要麼就橫跨左右兩邊(子序列包含了中間元素)
2._合。整個數組的最大累加和就是max(左邊的最大和, 右邊的最大和, 跨越兩邊的最大和)
於是可以:a.先分別求左右兩個部分的最大累加和,這是一個遞迴的過程;
b.求跨越左右兩邊的子序列能夠給出的最大累加和;
c.返回三個和中的最大值,作為整個序列的最大累加和。
關鍵是b.過程。其實也很簡單,以中間元素為起點,分別向左右兩邊擴充,求出在左邊子序列中,尾碼序列能達到的最大累加和;以及
右邊序列中,首碼序列能達到的最大累加和,這倆累加和加起來即可。
設中間節點的下標為m,那所謂的左邊子序列的尾碼就是:nums[...m-2, m-1, m],右邊子序列的首碼就是nums[m+1, m+2...].
1 # @param {integer[]} nums 2 # @return {integer} 3 def maxSubArray(self, nums): 4 if len(nums)==0: 5 return 0 6 return self.recur(nums, 0, len(nums)-1) 7 8 9 def recur(self, nums, start, end):10 if start==end: #one element11 return nums[start]12 mid=(start+end)/213 leftAns=self.recur(nums, start, mid)14 rightAns=self.recur(nums, mid+1, end)15 leftMax=nums[mid]16 rightMax=nums[mid+1]17 tmp=018 for i in range(mid, start-1, -1): #直接加到最後吧19 tmp+=nums[i]20 leftMax=max(leftMax, tmp)21 tmp=022 for i in range(mid+1, end+1):23 tmp+=nums[i]24 rightMax=max(rightMax, tmp)25 return max(leftAns, rightAns, leftMax+rightMax)
LeetCode#53 Maximum Subarray