方法1:暴力法 超时
枚举
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
#暴力法
res = nums[0]
for i in range(0,len(nums)):
sum_ = 0
for j in range(i,len(nums)):
sum_ += nums[j]
res = max(res,sum_)
return res
方法2:动态规划
动态规划问题,弄清楚三点:
1、重复子问题;
2、最优子结构;
3、无后效性。
动态规划:
1、状态定义;
2、状态转移方程;
3、初始化;base case
4、输出;
5、思考状态压缩。
可以用递归去求,但是会存在重叠子问题,加个备忘录可以解决重复问题。
思路:
状态定义:
dp[i],表示以nums[i]为结尾的最大子序和
状态转移方程:
dp[i]=max(nums[i],dp[i-1]+nums[i])
初始化:
dp[:] = float('-inf')
返回值:
max(dp) 在所有结尾中最大的子序和
代码如下:
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
#动态规划
dp = [float('-inf')] * len(nums)
dp[0] = nums[0]
for i in range(1,len(nums)):
dp[i] = max(nums[i],dp[i-1] + nums[i])
return max(dp)
空间优化:
上面的空间复杂为O(N),因为dp[i]只与前面的dp[i-1]有关,所以我们可以不用数组,只用一个变量来记录,优化后,空间复杂度为O(1)
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
#动态规划
res = nums[0]
dp= nums[0]
for i in range(1,len(nums)):
dp = max(nums[i],dp + nums[i])
res = max(res,dp)
return res
方法3:贪心
遍历,sum_是数字之和,如果sum_ > 0,则就加上nums[i],否则 就把nums[i]赋值给sum_,取res和sum_较大的值
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
#贪心
res = nums[0]
sum_ = 0
for num in nums:
if sum_ > 0:
sum_ += num
else:
sum_ = num
res = max(res,sum_)
return res
方法4:分治
最大子序和要么在左边,要么在右边,要么通过中间,前两种情况是可以递归处理的,第三种情况可以直接计算出来
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
#分治
n = len(nums)
#终止条件
if n == 1:
return nums[0]
else:
left = self.maxSubArray(nums[0:len(nums) // 2])
right = self.maxSubArray(nums[len(nums) // 2 : len(nums)])
max_1 = nums[len(nums) // 2 - 1]
temp = 0
for i in range(len(nums) // 2 - 1,-1,-1):
temp += nums[i]
max_1 = max(temp,max_1)
max_r = nums[len(nums) // 2]
temp = 0
for i in range(len(nums) // 2,len(nums)):
temp += nums[i]
max_r = max(temp,max_r)
return max(right,left,max_1 + max_r)
方法1:
时间复杂度:O(N^N)
空间复杂度:O(1)
方法2:
时间复杂度:O(N)
空间复杂度:O(1)
方法3:
时间复杂度:O(N)
空间复杂度:O(1)
方法4:
时间复杂度:O(N)
空间复杂度:O(logN)