LeetCode#53 Maximum Subarray

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=0
10         maxEnd=0
11         for i, n in enumerate(nums):
12             sm+=n
13             if sm>maxSum:
14                 maxSum=sm
15                 maxBegin=begin
16                 maxEnd=end
17             if sm<=0:
18                 begin=i+1
19                 end=i+1
20                 sm=0
21             else:
22                 end+=1
23         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 element
11             return nums[start]
12         mid=(start+end)/2
13         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=0
18         for i in range(mid, start-1, -1):  #直接加到最后吧
19             tmp+=nums[i]
20             leftMax=max(leftMax, tmp)
21         tmp=0
22         for i in range(mid+1, end+1):
23             tmp+=nums[i]
24             rightMax=max(rightMax, tmp)
25         return max(leftAns, rightAns, leftMax+rightMax)

 


 


 

 

 

posted @ 2015-08-04 22:49  曾可爱  阅读(133)  评论(0编辑  收藏  举报