给定一个整数数组,找出总和最大的连续数列,并返回总和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
- 解法一:动态规划
思想:
dp[i]代表dp[0:i]最大的连续数列和,求dp[i]我们有两种情况,要么选择nums[i] + dp[i-1], 要么直接选择nums[i];而max_value 记录着遍历过的子序列最大值。
即状态转移方程:dp[i] = max(dp[i-1] + nums[i], nums[i])
class Solution(object):
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
lens = len(nums)
dp = [0]*lens
dp[0] = nums[0]
max_value = nums[0]
for i in range(1,lens):
if dp[i-1] > 0:
dp[i] = nums[i]+dp[i-1]
else:
#丢掉前面,自立门户
dp[i] = nums[i]
#和最大值比较,看是否需要更新
if dp[i] > max_value:
max_value = dp[i]
return max_value
- 解法二:贪心
思想:
本题其实直接通过贪心策略解决,运用temp统计子数组的和,sum更新最大和,如果temp + nums[i] > 0, 说明当前子数组还是一个正数,我们加上后面的数组还有可能更大(至少不亏,或则最大和已经出现)我们就继续累加,如果temp + nums[i] < 0 说明当前数组为负数,是一个负担,再加上后面,还不如重新开始统计,即temp = 0,继续累加。
class Solution(object):
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
temp = nums[0]
sums = nums[0]
lens = len(nums)
for i in range(1,lens):
temp += nums[i]
if temp > sums:
sums = temp
if temp < 0:
#如果temp为负,它必定是累赘对后面来说,直接不要
temp = 0
return sums
- 解法三:分治
思想:
分治的基本思想就是将大问题化解为小问题,小问题继续化解,复杂问题简单化。
首先分析如下:
任意一个序列,最大子序列只有3种情况
1.出现在数组左边;
2.出现在数组右边;
3.出现在数组中间部分,即横跨左右;
那么我们要求的其实就是这三者中的最大值,即求数组左边的最大值,数组右边的最大值,数组中间部分的最大值。
将数组划分为左右两部分,便可求得左右子数组的最大,在求左右子数组的过程中,leftsum,rightsum均从中间向两端相加,那么
leftsum+rightsum即为中间部分相加的最大值。
class Solution(object):
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
def MaxSum(nums,left_position,right_position):
if left_position == right_position:
return nums[left_position]
mid = left_position+(right_position-left_position)/2
left_max_value = -float("inf")
right_max_value = -float("inf")
left_max_value = MaxSum(nums,left_position,mid)
right_max_value = MaxSum(nums,mid+1,right_position)
#float("inf")->正无穷 float("-inf")-->负无穷
left_sum = 0
left_max_sum = -float("inf")
#从中间向两边加
for i in range(mid,left_position-1,-1):
left_sum += nums[i]
if left_sum > left_max_sum:
left_max_sum = left_sum
right_sum = 0
right_max_sum = -float("inf")
#从中间向两边加
for j in range(mid+1,right_position+1):
right_sum += nums[j]
if right_sum > right_max_sum:
right_max_sum = right_sum
#如果数组中数值都为负,这里最大的就会是0,故要初始话无穷小
return max(left_max_value,left_max_sum+right_max_sum,right_max_value)
return MaxSum(nums,0,len(nums)-1)