leetcode刷题(面试题 16.17)

给定一个整数数组,找出总和最大的连续数列,并返回总和。

示例:

输入: [-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)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值