LeetCode 53. 最大子数组和

53. 最大子数组和

  

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组 是数组中的一个连续部分。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

示例 2:

输入:nums = [1]
输出:1

示例 3:

输入:nums = [5,4,-1,7,8]
输出:23

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104

进阶:如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的 分治法 求解。

思路:

  • 动态规划 方式1:

    判断 dp[i] = dp[i-1] + nums[i] 中,dp[i-1] 是起到 正向作用还是负向作用

    判断 nums[i] 是否要加上之前的 dp[i-1],有两种情况:
    • 当 dp[i-1] > 0 起正向作用时,则可以加上之前的dp[i-1];
    • 反之 当 dp[i-1] < 0 起负向作用时,则不加

  • 动态规划 方式2(方式1的优化版):

    其实上述方式并不是最优的,因为每次遍历我只需要判断之前的 dp[i-1] 的正负即可,所以可以用一个变量 pre 来代替和复用,并不需要额外构造dp数组。这样空间复杂度可降至O(1)

时间复杂度:O(N)

空间复杂度:方式1 O(N),方式2 O(1)

// 动态规划-1 【空间复杂度O(n) 时间复杂度O(n)】
// 思路:之前的题,是已经选好了dp[i-1],然后来考虑要不要选第i个值。这道题是一定要选第i个值,然后再考虑要不要选第dp[i-1]。
func maxSubArray(nums []int) int {
    n := len(nums)
    dp := make([]int, n)
    dp[0] = nums[0]
    res := nums[0]

    for i := 1; i < n; i++ {
        // 判断 nums[i] 是否要加上之前的dp[i-1],有两种情况:
        // 当 dp[i-1] > 0 起正向作用时,则可以加上之前的dp[i-1];反之 当 dp[i-1] < 0 起负向作用时,则不加
        dp[i] = max(dp[i - 1] + nums[i], nums[i])
        res = max(res, dp[i])
    }

    return res
}

// 动态规划-2 【上面代码的优化版 → 空间复杂度O(1) 时间复杂度O(n)】  
// 每次遍历我只需要判断之前的dp[i-1]的正负即可,所以可以用一个变量preSum来复用
// 1、判断 nums[i]是否要加上之前的前缀和 preSum,有两种情况:
// 2、当 preSum > 0 对最大子数组和起正向作用时,则可以加上之前的preSum;
// 3、反之,当 preSum < 0 对最大子数组和起负向作用时,则不加
func maxSubArray(nums []int) int {
    res, preSum := nums[0], 0

    for i := 0; i < len(nums); i++ {
        preSum = max(preSum + nums[i], nums[i])
        res = max(res, preSum)
    }
    return res
}

func max(a, b int) int {
    if a > b {
        return a
    }

    return b
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值