您的位置:首页 > 其它

LeetCode 最大子序和

2019-03-14 10:16 92 查看

题目

  给定一个整数数组

nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例

input: [-2, 1, -3, 4, -1, 2, 1, -5, 4]
output: 6

解法

动态规划 ( Python )

class Solution:
def maxSubArray(self, nums) -> int:
tmp = nums[0]
maxlen = tmp
for i in range(1, len(nums)):
if(tmp < 0):
tmp = nums[i]
else:
tmp += nums[i]
maxlen = max(maxlen, tmp)
return maxlen
基本思路

   动态规划的思想是最优解包含的每个子问题的解也是最优的。代码中的

tmp
代表的就是子问题的最优解,不过因为这道题中有负数的存在,所以子问题的最优解也可能是负数,所以还需要和 0 进行比较。另外,这道题没有代价的概念,只有值的累加,不需要保存每个子问题的最优解,只需要上一轮的最优解即可。
maxlen
变量不是主角,其作用只是记录当前最大值而已。

复杂度分析

  

for
循环的时间开销为O(N)O(N)O(N),内部为
O(1)
,所以时间复杂度为O(N)O(N)O(N)。空间复杂度为O(1)O(1)O(1)

分冶法 ( Python )

class Solution:
def maxSubArray(self, nums) -> int:
length = len(nums)
if(length <= 0):
return 0
return self.calSubArray(nums, 0, length - 1)

def calSubArray(self, nums, left, right):
if(left == right):
return nums[left]
mid = (left + right) // 2
maxleft = self.calSubArray(nums, left, mid)
maxright = self.calSubArray(nums, mid + 1, right)

#从mid为起点,向左计算最大子序列和, ct意为continuity,连续的
tmp = 0
left_ct = nums[mid]
for i in range(mid, left - 1, -1):
tmp += nums[i]
left_ct = max(tmp, left_ct)

#以mid为起点,向右计算最大子序列和
tmp = 0
right_ct = nums[mid + 1]
for i in range(mid + 1, right + 1):
tmp += nums[i]
right_ct = max(tmp, right_ct)

#计算左右子序列交界地带最大子序列和
maxCross = left_ct + right_ct
return max(maxleft, maxright, maxCross)
基本思路

  分冶法是将原问题逐步划分成一个个更小的子问题,再合并的过程。

maxleft
maxright
是被划分出的左右两个序列的最大子序和,但这两者是不能直接相加的,因为它们在序列里有可能不是连续的。另外,这两个序列原先是交接的,它们的交界地带有可能存在一个更大的子序列和,所以需要以
mid
为起点,分别向左右两边累加,求得交界地带最大值
。下面举两个例子。

input: [2, -1, 2]
说明:这个序列会被划分成[2], [-1, 2]两个子序列。
最大子序列和分别为 2,2。但因为两个2索引不是连续的,所以不能直接相加

input: [-1, 2, 1, 2, -1, 1]
说明:这个序列会被划分成[-1, 2, 1],[2, -1, 1]。
左侧最大序列和为 2,右侧最大序列和也是2。但是它们的交界地带有一个更大的子序列[2, 1, 2]
复杂度分析

  分冶法的时间复杂度为O(N2)O(N^2)O(N2), 因为

calSubArray
被调用了n次,这和二分法是不同的,另外递归实现也会带来一定的开销。空间复杂度为 O(1)O(1)O(1)。

参考资料
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: