Leetcode-最大子序和(53)
题目描述:给定一个整数数组 nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:输入: [-2,1,-3,4,-1,2,1,-5,4],输出: 6
思路:一开始除了暴力破解以外没有想到什么其他的方法,通过官方题解学习到了三种方法,分别为:贪心算法、分治法和DP动态规划法。
(1)贪心算法。总体思路为,每一步都选择局部最优解,则到达最后一步时所获得的也是整体最优解。具体来说就是遍历整个数组,在每个位置找到当前位置的最大和cur_max,然后更新整体最大和final_max.
1 class Solution: 2 def maxSubArray(self, nums: List[int]) -> int: 3 cur_max,final_max = nums[0],nums[0] 4 for word in nums[1:]: 5 cur_max = max(word,word+cur_max) 6 if cur_max > final_max: 7 final_max = cur_max 8 return final_max
时间复杂度:O(n) 空间复杂度:O(1)
(2)分治法。分治法的主要思想为,将原问题划分为若干个子问题,递归地解决子问题,合并子问题的解以得到原始问题的最终解。
在本题中,以数组nums最中间的字符为界,具有最大和的连续子数组可以分为三种情况:
- 递归找到左半部分具有最大和的子序列
- 递归找到右半部分具有最大和的子序列
- 从中间开始扫描,找到跨越中界线的具有最大和的子序列。
- 三者中最大的即为最终找到的具有最大和的子序列
6>4>3,故最终结果为3
1 class Solution: 2 def maxSubArray(self, nums: List[int]) -> int: 3 n = len(nums) 4 if n == 1: 5 return nums[0] 6 else: 7 left_max = self.maxSubArray(nums[:len(nums)//2]) #递归左半部分 8 right_max = self.maxSubArray(nums[len(nums)//2:]) #递归右半部分 9 #从中界线开始向左扫描 10 l_max = nums[len(nums)//2-1] 11 l_tmp = 0 12 for i in range(len(nums)//2-1,-1,-1): 13 tmp_l += nums[i] 14 max_l = max(tmp_l,max_l) 15 max_r = nums[len(nums)//2] 16 #从中界线开始向右扫描 17 tmp_r = 0 18 for i in range(len(nums)//2,len(nums)): 19 tmp_r += nums[i] 20 max_r = max(tmp_r,max_r) 21 return max(max_left,max_right,max_l+max_r)
时间复杂度:O(nlogn) 空间复杂度:O(1)
(3)不太像动态规划法的动态规划法。用cur_sum表示当前最大连续子序列和,用ans表示最终结果。
遍历nums中的每一个数字number。若number>0,则该number对最后结果有增益效果(cur_sum加上一个正数一定大于当前的cur_sum),更新cur_sum+=number;若number<0,则该number对最后结果没有增益效果(因为该负数的存在一定会让最后的总和变小),因而舍弃该number,更新cur_sum = number。每遍历一个数字,更新ans=max(ans,cur_sum)。
1 class Solution: 2 def maxSubArray(self, nums: List[int]) -> int: 3 ans = nums[0] 4 cur_sum = 0 5 for i in nums: 6 if cur_sum >= 0 : 7 cur_sum += i 8 else: 9 cur_sum = i 10 ans = max(ans,cur_sum) 11 return ans
时间复杂度:O(nlogn) 空间复杂度:O(1)