53 | Maximum Subarray | 40.10% | 子数组和的最大值 |
动态规划法Dynamic Programming:时间复杂度为o(n),试想从头遍历这个数组。对于数组中的其中一个元素,它只有两个选择: 1. 要么加入之前的数组加和之中(跟别人一组) 2. 要么自己单立一个数组(自己单开一组)。 构造一个局部最优值和一个全局最优值 分治法:时间复杂度为o(nlogn),将数组均分为两个部分,那么最大子数组会存在于: 1. 左侧数组的最大子数组 2. 右侧数组的最大子数组 3. 左右数组分界处的最大子数组 |
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Jan 24 22:02:47 2018
@author: vicky
"""
class Solution:
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
# #时间超了
# x=min(nums)
# for i in range(len(nums)):
# for j in range(i,len(nums)):
# x=max(x,sum(nums[i:j+1]))
# return x
#法1:动态规划法Dynamic Programming:时间复杂度为o(n)
#试想从头遍历这个数组。对于数组中的其中一个元素,它只有两个选择:
# 1. 要么加入之前的数组加和之中(跟别人一组)
# 2. 要么自己单立一个数组(自己单开一组)
#所以对于这个元素应该如何选择,就看他能对哪个组的贡献大。
#如果跟别人一组,能让总加和变大,还是跟别人一组好了;
#如果自己起个头一组,自己的值比之前加和的值还要大,那么还是自己单开一组好了。
#所以利用一个l数组,记录每一轮的最大值,
#l表示当前这个元素是跟之前数组加和一组还是自己单立一组好,然后维护一个全局最大值即为答案。
l=0 #局部最大值,变换起点,大于0则起点不变,小于0则起点变为当前值
g=nums[0] #全局最大值,变换终点
for i in range(len(nums)):
if l>0:#如果当前的局部最大值l是为正的,则加上数组的当前查找值nums[i]
l=l+nums[i]
else:#如果l为负,则加上他不如不要,所以直接用当前查找值nums[i]为新的起点
l=nums[i]
g=max(g,l)#全局最优=当前的局部最优or还是原来的全局最优
return g
#更简便写法,善用max()对比而不用if判断
l=0
g=nums[0]
for i in range(len(nums)):
l=max(nums[i],l+nums[i])#用max对比l和0的大小
g=max(g,l)
return g
#法2:分治法:时间复杂度为o(nlogn)
#将数组均分为两个部分,那么最大子数组会存在于:
# 1. 左侧数组的最大子数组
# 2. 右侧数组的最大子数组
# 3. 左右数组分界处的最大子数组
class Solution(object):
def maxSubArrayHelper(self,nums, l, r):
if l > r:
return -2147483647
m = (l+r) / 2
leftMax = sumNum = 0
for i in range(m - 1, l - 1, -1): # 从中间向左遍历
sumNum += nums[i]
leftMax = max(leftMax, sumNum)
rightMax = sumNum = 0
for i in range(m + 1, r + 1): # 从中间向右遍历
sumNum += nums[i]
rightMax = max(rightMax, sumNum)
leftAns = self.maxSubArrayHelper(nums, l, m - 1) #递归
rightAns = self.maxSubArrayHelper(nums, m + 1, r)
return max(leftMax + nums[m] + rightMax, max(leftAns, rightAns))
def maxSubArray(self, nums):
return self.maxSubArrayHelper(nums, 0, len(nums) - 1)
if __name__ == "__main__":
nums=[1]
print(Solution().maxSubArray(nums))