【Leetcode】53. Maximum Subarray 解题报告

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dpengwang/article/details/86656101

方法1:直觉法

求连续子数组的最大和,就是相当于用一个框框起数组中的若干个数,使其和最大,这个框该怎么选?
我们用curr_sum表示当前框里框住的元素和。
首先固定框的左边,移动框的右边,如果curr_sum大于0,我们就右移右边界并求和,记录当前的最大值。如果curr_sum小于0,我们就将框的左边移动到当前位置(代码中的表现就是让curr_sum归零),然后再右移右边界并求curr_sum,记录当前的最大值

为什么要在curr_sum小于等于0的时候将框的左边界移动到当前位置?
因被框住的部分和小于等于0,他们对后面产生的和只会有减少左右不会有增加作用,所以要舍弃掉,当前的元素是一个leader,之前被框住的一坨是一个小团队A(假设不用按人头发工资),现在leader和A要组成更强的团队,如果整个A对外的输出都不是正的,那为啥还要跟你组队呢。只要A的输出为正的,那就留着。

class Solution:
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        curr_sum = -float("inf")
        res = curr_sum
        for i in nums:
            if curr_sum < 0:
                curr_sum = i
            else:
                curr_sum += i
            res = max(res, curr_sum)
        return res

在这里插入图片描述

方法2:dp法

其实就是直觉法更形式化的方法,我们用dp[i]表示包含第index=i元素的最大连续子数组和,那么很容易写出递推方程

dp[i] = a[i] if dp[i-1] <=0 else dp[i-1] + a[i]
即
dp[i] = max(a[i] + dp[i-1],  a[i])

现实中的解释就是,如果dp[i-1]小于等于0,那你对我的增加一点用处都没有,那么就舍弃掉你。

class Solution:
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        res =nums[0]
        dp = [nums[0]]*len(nums)
        for i in range(1,len(nums)):
            dp[i] = max(dp[i-1]+nums[i], nums[i])
            res = max(res, dp[i])
        return res

在这里插入图片描述

方法3: 递增栈法

我们要找最大和子数组,也就是最大的 s u m i s u m j sum_{i} - sum_{j} (i<j),其中 s u m i sum_{i} 表示array[0:i]的和,不考虑时间复杂度的话,两个for循环即可解决问题。我们通过维护一个递增栈,就能用O(n)的时间复杂度来求得最大差。
我们先求 s u m i sum_{i}

nums = [-2, 1, -3 ,4, -1, 2, 1, -5, 4]
sum =  [-2, -1, -4, 0, -1, 1, 2, -3, 1]

我们维护一个递增栈,创建一个stack,遍历sum中的元素并按照如下方法入栈

  • 如果栈为空,将当前元素入栈
  • 如果栈顶元素小于当前元素,将当前元素入栈
  • 如果栈顶元素大于当前元素,popstack,直到栈顶元素小于当前元素
  • 每次操作完毕后求栈顶减去栈底元素来更新res
    因为是顺序入栈的,所以我们可以保证栈底元素的index总是小于栈顶元素的index,因为栈是递减的,所以在index=i的时候,栈底存储的一定是sum[0:i]中最小的元素,栈顶一定是sum[0:i]中最大的元素。
    这里有个小trick,我们把res的初始值设为nums中的最大值,这样可以避免nums全为负导致的异常情况,把stack初始值设为0可以避免num全为正导致的异常情况。
    stack的出栈入栈情况如下:
i sum[i] stack res
-1 [0] 4
0 -2 [-2] 4
1 -1 [-2,-1] 4
3 -4 [-4] 4
4 0 [-4,0] 4
5 -1 [-4,-1] 4
6 1 [-4,-1,1] 5
7 2 [-4,-1,2] 6
8 -3 [-4,-3] 6
9 1 [-4,-3,1] 6

AC代码

class Solution:
    def maxSubArray(self,nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        res = nums[0]
        for i in range(len(nums)):
            res = max(res, nums[i])
            if i == 0:
                continue
            else:
                nums[i] += nums[i-1]
        stack = [0]
        for number in nums:
            if len(stack) == 0 or (len(stack)!=0 and stack[-1] < number):
                stack.append(number)
                res = max(res, stack[-1] - stack[0])
            else:
                while(len(stack) and stack[-1] >= number):
                    stack.pop()
                stack.append(number)
        return res

猜你喜欢

转载自blog.csdn.net/dpengwang/article/details/86656101