Leetcode 53-Maximum Subarray
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
.
分析:这题就是求最大连续字串的和,或者说是求和最大的连续子数组
此题最简单的是暴力,但是暴力为O(N^2), 超时。
另外可以采用动态规划来求解,关键是如何转换为动态规划问题,即如何表述成动态规划问题。
我们用local[i]来表示以A[i]结尾的连续子数组的最大和,那么local[0] = A[0], local[1]等于要么local[0]+A[1] 要么就等于A[1]本身,关键看两者谁更大,于是便得到递归式local[i+1] = max(local[i]+A[i+1], A[i+1]),local数组中的最大值即为所求。
参考链接: http://blog.csdn.net/lu597203933/article/details/44962163
典型的动态规划---"全局最优和局部最优解法"
1、基本思路
1)基本变量:全局最优,到当前元素的最优解
2)动态规划递推式:
假设我们已知第i步的global[i](全局最优)和local[i](局部最优),那么第i+1步的表达式是:
local[i+1]=max(A[i+1], local[i]+A[i]),
就是局部最优是一定要包含当前元素,
所以不然就是上一步的局部最优local[i]+当前元素A[i+1](因为local[i]一定包含第i个元素,所以不违反条件),
但是如果local[i]是负的,那么加上他就不如不需要的,所以不然就是直接用A[i+1];
global[i+1]=max(local[i+1],global[i]),
有了当前一步的局部最优,那么全局最优就是当前的局部最优或者还是原来的全局最优
(所有情况都会被涵盖进来,因为最优的解如果不包含当前元素,那么前面会被维护在全局最优里面,如果包含当前元素,那么就是这个局部最优)。
2、复杂度
1)时间上只需要扫描一次数组,所以时间复杂度是O(n)。
2)空间上我们可以看出表达式中只需要用到上一步local[i]和global[i]就可以得到下一步的结果,
所以我们在实现中可以用一个变量来迭代这个结果,不需要是一个数组,也就是如程序中实现的那样,
所以空间复杂度是两个变量(local和global),即O(2)=O(1)。
class Solution(object):
def maxSubArray(self, nums):#时间复杂度O(n)
"""
:type nums: List[int]
:rtype: int
"""
if len(nums)==0:
return 0
maxsum=nums[0]
currsum=nums[0]
for i in range(1,len(nums)):
#考虑以当前位置为结尾的子数组
currsum=max(nums[i],currsum+nums[i])#当前元素的局部最优:1)当前元素 2)上一元素局部最优加上当前元素(保证是连续的子数组)
maxsum=max(maxsum,currsum)#全局最优:当前最优与上一全剧最优的最大值
return maxsum
Letcode152-Maximum Product Subarray
Find the contiguous subarray within an array (containing at least one number) which has the largest product.
For example, given the array [2,3,-2,4]
,
the contiguous subarray [2,3]
has the largest product = 6
.
链接:https://leetcode.com/problems/maximum-product-subarray/
这道题跟 Maximum Subarray 模型上和思路上都比较类似,还是用一维动态规划中的“局部最优和全局最优法”。这里的区别是维护一个局部最优不足以求得后面的全局最优,这是由于乘法的性质不像加法那样,累加结果只要是正的一定是递增,乘法中有可能现在看起来小的一个负数,后面跟另一个负数相乘就会得到最大的乘积。我们只需要在维护一个局部最大的同时,在维护一个局部最小,这样如果下一个元素遇到负数时,就有可能与这个最小相乘得到当前最大的乘积和,这也是利用乘法的性质得到的。
以max_local[i]表示以A[i]结尾的连续数组的最大乘积,min_local[i]表示以A[i]结尾的连续数组的最小乘积,转移方程为:
max_copy[i] = max_local[i]
max_local[i + 1] = Max(max_local[i] * A[i+1], A[i+1], min_local * A[i+1])
min_local[i + 1] = Min(max_copy[i] * A[i+1], A[i+1], min_local * A[i+1])
说明:在max_local[i] * A[i+1], A[i+1], min_local * A[i+1]选出最小和最大的值,作为当前的局部最大最小值
参考链接:http://blog.csdn.net/linhuanmars/article/details/39537283
class Solution(object):
def maxProduct(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if not nums:
return 0
if len(nums)==1:
return nums[0]
max_local=nums[0]
min_local=nums[0]
max_global=nums[0]
for i in range(1,len(nums)):
max_copy=max_local
max_local=max(max_local*nums[i],nums[i],min_local*nums[i])
min_local=min(max_copy*nums[i],nums[i],min_local*nums[i])
max_global=max(max_local,max_global)
return max_global