zl程序教程

您现在的位置是:首页 >  后端

当前栏目

剑指 Offer 42. 连续子数组的最大和

数组 最大 Offer 连续 42
2023-09-14 09:13:11 时间

剑指 Offer 42. 连续子数组的最大和

难度: e a s y \color{Green}{easy} easy


题目描述

输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。

要求时间复杂度为O(n)。

示例1:

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

提示:

  • 1 < = a r r . l e n g t h < = 1 0 5 1 <= arr.length <= 10^5 1<=arr.length<=105
  • − 100 < = a r r [ i ] < = 100 -100 <= arr[i] <= 100 100<=arr[i]<=100

注意:本题与主站 53 题相同:https://leetcode-cn.com/problems/maximum-subarray/


算法

常见解法时间复杂度
暴力搜索 O ( n 2 ) O(n^2) O(n2)
分治思想 O ( n l o g n ) O(nlogn) O(nlogn)
动态规划 O ( n ) O(n) O(n)

(动态规划)

  • 状态定义: 设动态规划列表 d p dp dp d p [ i ] dp[i] dp[i] 代表以元素 n u m s [ i ] nums[i] nums[i] 为结尾的连续子数组最大和。

为何定义最大和 dp[i] 中必须包含元素 nums[i] :保证 dp[i] 递推到 dp[i+1] 的正确性;如果不包含 nums[i] ,递推时则不满足题目的 连续子数组 要求。

  • 转移方程: 若 d p [ i − 1 ] ≤ 0 dp[i−1]≤0 dp[i1]0 ,说明 d p [ i − 1 ] dp[i−1] dp[i1] d p [ i ] dp[i] dp[i] 产生负贡献,即 d p [ i − 1 ] + n u m s [ i ] dp[i−1]+nums[i] dp[i1]+nums[i] 还不如 n u m s [ i ] nums[i] nums[i] 本身大。

    • d p [ i − 1 ] > 0 dp[i−1]>0 dp[i1]>0 时:执行 d p [ i ] = d p [ i − 1 ] + n u m s [ i ] dp[i]=dp[i−1]+nums[i] dp[i]=dp[i1]+nums[i]
    • d p [ i − 1 ] ≤ 0 dp[i−1]≤0 dp[i1]0 时:执行 d p [ i ] = n u m s [ i ] dp[i]=nums[i] dp[i]=nums[i]
  • 初始状态: d p [ 0 ] = n u m s [ 0 ] dp[0]=nums[0] dp[0]=nums[0],即以 n u m s [ 0 ] nums[0] nums[0] 结尾的连续子数组最大和为 n u m s [ 0 ] nums[0] nums[0]

  • 返回值: 返回 d p dp dp 列表中的最大值,代表全局最大值。

在这里插入图片描述

复杂度分析

  • 时间复杂度 O ( n ) O(n) O(n)

  • 空间复杂度 : O ( 1 ) O(1) O(1)

C++ 代码

使用 res 代表最终的答案,s 表示前 i - 1 项的值, 如果前 i - 1 项的值小于 0s 等于当前的数 num,如果大于 0, 说明可以加上当前的数字 num,继续往后运算。

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int res = INT_MIN, s = 0;
        for (auto x : nums) {
            if (s < 0) s = 0;
            s += x;
            res = max(res, s);
        }
        return res;
    }
};

参考链接