最大子序和
题目描述:
做题思路:
- 第一种:这种方法比较容易想到,但是写起来需要仔细推一推。我们先是从0开始,定义
temp
和maxi
为nums[0]
,然后开始从1开始循环,即从列表nums
的第二个数开始,先让它和第一个数相加,看其是否大于自己本身,如果大,则最大子序和很有可能会出现在后面序列中,然后将此时的最大值重新赋值给maxi
,然后将前面temp + nums[i]
又赋值给temp
,以此类推。反之,如果小,则我们重新以这个元素为起点开始往下找最大子序和,同时也记录最大值赋给maxi
。
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
lens = len(nums)
temp = maxi = nums[0]
for i in range(1, lens):
if temp + nums[i] > nums[i]:
maxi = max(maxi, temp + nums[i])
temp = temp + nums[i]
else:
temp = nums[i]
maxi = max(maxi, temp)
return maxi
- 第二种:这个方法是学习了别人的方法,官方叫贪心算法。确实特别厉害,从开始一直在遍历数组然后重复取最大值,如果
temp + nums[i]
最大,则继续往下加求得最大子序,如果nums[i]
最大,则从这个数重新开始往下找最大子序。通过不断地更新当前元素、当前元素位置的最大和还有全部的最大和得到最大子序和。
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
lens = len(nums)
temp = maxi = nums[0]
for i in range(1, lens):
temp = max(temp + nums[i], nums[i])
maxi = max(maxi, temp)
return maxi
- 第三种:这个方法也不算是新思路,就是在第一种方法的基础上做了些改进,减少了代码量,复杂度仍然是O(n),所以运行速度上变化没有很大,而且受到点网络影响。但是这个思路也是简化了很多,我们只需要找到那个大于零的数字,然后往下找最大子序和就可以了,因为容易推理到,最大子序的第一个数字必须要大于零,所以这个方法也很简单,找到大于零的数然后往后一直试就好。
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
lens = len(nums)
temp = maxi = nums[0]
for i in range(1, lens):
if temp > 0:
temp = temp + nums[i]
else:
temp = nums[i]
maxi = max(temp, maxi)
return maxi
- 第四种:分治法。我对这个方法其实不是特别了解,但是通过学习不同大佬的方法,我也尝试写了下。代码复杂度是O(nlogn),这个方法就是把数组分成三部分,要么最大子序在前半段,要么在后半段,要么就穿过中间。先通过递归的方法算出前半段和后半段的最大子序和,然后再计算中间的最大子序和,中间的这个也是先从中间到左边计算这段左半边的最大子序和,同理又计算右半边,然后加在一起就是中间的最大子序和。最后比较三个最大子序和的大小,求出整个数组的最大子序和。
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
lens = len(nums)
maxi = nums[0]
if lens == 1:
return maxi
else:
maxi_left = self.maxSubArray(nums[0:lens // 2])
maxi_right = self.maxSubArray(nums[lens // 2 : lens])
maxi_1 = nums[lens // 2 - 1]
temp = 0
for i in range(lens // 2 - 1, -1, -1):
temp += nums[i]
maxi_1 = max(temp, maxi_1)
maxi_2 = nums[lens // 2]
temp = 0
for i in range(lens // 2, lens):
temp += nums[i]
maxi_2 = max(temp, maxi_2)
maxi = maxi_1 + maxi_2
return max(maxi_left, maxi_right, maxi)