题目链接

牛客网

题目描述

{6, -3, -2, 7, -15, 1, 2, 2},连续子数组的最大和为 8(从第 0 个开始,到第 3 个为止)。

解题思路

动态规划解析:

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

    • 为何定义最大和 dp[i] 中必须包含元素 nums[i] :保证 dp[i] 递推到 dp[i+1] 的正确性;如果不包含 nums[i] ,递推时则不满足题目的 连续子数组 要求。
  • 转移方程: 若 dp[i−1]≤0 ,说明 dp[i−1] 对 dp[i] 产生负贡献,即 dp[i−1]+nums[i] 还不如 nums[i] 本身大。

    • 当 dp[i−1]>0 时:执行dp[i]=dp[i−1]+nums[i] ;
    • 当 dp[i−1]≤0 时:执行 dp[i]=nums[i] ;
    • 初始状态: dp[0]=nums[0],即以 nums[0] 结尾的连续子数组最大和为 nums[0] 。
  • 返回值: 返回 dp 列表中的最大值,代表全局最大值。

42. 连续子数组的最大和 - 图1

空间复杂度降低:

  • 由于 dp[i] 只与 dp[i-1] 和 nums[i] 有关系,因此可以将原数组 nums 用作 dp 列表,即直接在 nums 上修改即可。
  • 由于省去 dp 列表使用的额外空间,因此空间复杂度从 O(N) 降至 O(1) 。
  1. class Solution {
  2. public:
  3. int FindGreatestSumOfSubArray(vector<int> array) {
  4. int n = array.size();
  5. if(n==0)
  6. return 0;
  7. int max,dp;
  8. max = dp = array[0];
  9. for(int i=1;i<n;i++){
  10. if(dp<0)
  11. dp = array[i];
  12. else
  13. dp=dp+array[i];
  14. max = dp>max?dp:max;
  15. }
  16. return max;
  17. }
  18. };
  • 时间复杂度 O(N) : 其中 N 为字符串长度,动态规划需遍历计算 dp 列表。
  • 空间复杂度 O(1)

    返回最大和的子数组

    1. class Solution {
    2. public int[] maxSubArray(int[] nums) {
    3. // right为当前最大和的子数组右坐标
    4. // s为子数组长度
    5. // count为子数组中间计数
    6. int right = 0, s = 0, count = 0;
    7. // 利用dp不改变原始数组
    8. int[] dp = new int[nums.length];
    9. dp[0] = nums[0];
    10. for(int i = 1; i < nums.length; ++i){
    11. if(nums[i] < nums[i] + dp[i-1]){
    12. dp[i] = nums[i] + dp[i-1];
    13. // 连续 计数加一
    14. ++count;
    15. }else{
    16. dp[i] = nums[i];
    17. // 断开连续,重新计数
    18. count = 0;
    19. }
    20. if(dp[i] > dp[right]){
    21. // 出现更大的值,记录子数组右坐标和长度
    22. right = i;
    23. s = count;
    24. }
    25. }
    26. // 复制右坐标
    27. int[] res = new int[s + 1];
    28. for(int i = right - s, j = 0; i <= right; ++i,++j){
    29. res[j] = nums[i];
    30. }
    31. return res;
    32. }
    33. }