目录/Table of Content
53. Maximum Subarray (最大子数组)
大家好,我是一个喜欢研究算法、机械学习和生物计算的小青年,我的CSDN博客是:一骑代码走天涯
如果您喜欢我的笔记,那么请点一下关注、点赞和收藏。如果內容有錯或者有改进的空间,也可以在评论让我知道。😄
题目描述
这道题目先给一 个非空整数列表,然后要写一个函数用来返回它的子列表组合的最大的和。
例如系统给你 [-2,1,-3,4,-1,2,1,-5,4],你的函数应该返回整数 “6”,因为其中子列表 [4,-1,2,1] 的和是 6,是最大的组合。
因为Leetcode 地区服务器的不同,下面只能提供题目的英语版供大家参考。
题目原文(英语)
Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
A subarray is a contiguous part of an array.
Example 1:
Input: nums = [-2,1,-3,4,-1,2,1,-5,4]
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.
Example 2:
Input: nums = [1]
Output: 1
Example 3:
Input: nums = [5,4,-1,7,8]
Output: 23
解题方式(一) - 暴力解法 (brute force)
这个是最直观的:把所有子数列的可能都检查一遍,然后找出最大的和。但是,最致命的缺点就是这个方法就需要 O(n),时间复杂度太高,Leetcode 不让过。
时间复杂度:O(n2)
空间复杂度:O(1)
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
if len(nums) == 1:
return nums[0]
else:
max_sum = max(nums)
for i in range(1, len(nums)+1):
start = 0
end = start + i
while end <= len(nums):
if sum(nums[start:end]) > max_sum:
max_sum = sum(nums[start:end])
start += 1
end += 1
if sum(nums) > max_sum:
return sum(nums)
return max_sum
解题方式(二) - 动态规划 (dynamic programming (DP))
除了刚才的暴力算法,我们还有其它方法可以做这题。比如说,因为已知子列表的数字必须在列表上是连起来的,那我们就可以利用这个特点来简化咱们的算法,以下是两个咱们要考虑的特点:
- 任何子列表的和与正数相加,必定大于原本的子列表的和;
- 任何子列表的和与负数相加,必定小于原本的子列表的和;
因此,只要我们从第一位数字开始,如果顺着的数字和它相加后是正数,那就相加,然后跟 已有的最大和 (i.e., max_num,用列表最大的数字初始化) 比较看哪个大。
但如果子列表的和已经是非正数了,那就是说任何的正数子列表都能比它大,所以只需要和 已有的最大和 相比一次就可以了,如果后面是负数或者零, 已有的最大和 都不会因为有改变,如果是正数的话就直接替换它就可以了,所以我们可以直接从下一个顺位的数字重新开始合成新的子列表比较。
时间复杂度:O(n)
空间复杂度:O(1)
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
if len(nums) == 1:
return nums[0]
else:
max_sum = max(nums)
curr = nums[0]
nums_len = len(nums)
for i in range(1, nums_len):
if curr > 0:
curr += nums[i]
else:
curr = nums[i]
if curr > max_sum:
max_sum = curr
return max_sum
其实还有第三个解题方式,就是用分治法 (divide-and-conquer),但是有点麻烦,我偷下懶,所以不作敍述了。🤣