JZ42 连续子数组的最大和

99 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 12 天,点击查看活动详情

Day03 2023/01/10

题目链接

难度:简单

题目

输入一个长度为n的整型数组array,数组中的一个或连续多个整数组成一个子数组,子数组最小长度为1。求所有子数组的和的最大值。

数据范围:

1<=n<=2×1052×10^5 −100<=a[i]<=100

要求:时间复杂度为O(n),空间复杂度为O(n)

进阶:时间复杂度为 O(n),空间复杂度为 O(1)

示例

输入:[1,-2,3,10,-4,7,2,-5]
返回值:18
说明:经分析可知,输入数组的子数组[3,10,-4,7,2]可以求得最大和为18

思路


根据题目要求,数组中有正有负 ,而且要连续的子数组,所以我们一般先遍历数组,每次将数组中的元素加入到子数组中,但问题就是该元素是否要加入到子数组中,因为我们要求的时最大的连续子数组,数组元素加入当前最大连续子数组后有如下情况:

  • 子数组变小:
    • 该元素一定是负数,这时当前最大连续子数组的值就是加上这个这个元素后的值
  • 子数组变大:
    • 该元素一定是正数:
      1. 本次循环前一次循环的连续子数组是负数时,则本次循环的最大连续子数组的值就是当前元素
      2. 本次循环前一次循环的连续子数组是正数时,则本次循环的最大连续子数组的值就是当前元素值加上上一次循环的最大连续子数组
  • 子数组不变:
    • 则该元素为0,则最大连续子数组的值不变 所以这类有状态转移的问题可以考虑动态规划。
      具体做法:
  1. 可以用一个dp数组表示以下标i为终点的最大连续子数组和。
  2. 遍历数组,每次都添加到dp数组中,根据值的变化(即状态转移),在重新获取dp[i]的值
  3. 因为联系数组可能会断掉,每一段只能得到该段最大值,因此我们需要维护一个最大值。

关键点


  • 状态转移的语句包含了上述所有可能的状况, dp[i] = max(dp[i-1] + array[i], array[i])

算法实现


c++代码实现-动态规划

#include <vector>
class Solution {
public:
    int FindGreatestSumOfSubArray(vector<int> array) {
    //记录下标i位置的最大连续子数组和
    vector<int> dp (array.size(), 0);
    dp[0] = array[0];
    int maxsum = dp[0]; //记录最大连续子数组累加的值
    for (int i = 1; i < array.size(); i++) {
        //状态转移:连续子数组和最大值
        dp[i] = max(dp[i-1] + array[i], array[i]);
        //维护最大值,每一轮循环dp[i]值都可能改变
        maxsum = max(maxsum, dp[i]);
    }
    return maxsum; 
    }
};
  • 时间复杂度 O(n)O(n) --- 遍历整个数组,其中n为数组长度
  • 空间复杂度 O(n)O(n) --- 辅助数组的长度为n, 其中n为数组长度

总结

动态规划算法的基本思想是:将待求解的问题分解成若干个相互联系的子问题,先求解子问题,然后从这些子问题的解得到原问题的解;对于重复出现的子问题,只在第一次遇到的时候对它进行求解,并把答案保存起来,让以后再次遇到时直接引用答案,不必重新求解。动态规划算法将问题的解决方案视为一系列决策的结果。