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

83 阅读1分钟

image.png

这道题典型的用动态规划去解决。

方法一

方法一是用一个一维的数组 dp[i] 去存储结果,dp[i] 的含义是“以第i个元素结尾的子数组的元素之和最大值”,其中i的值为0~n-1,n是nums数组的大小。初始化 dp[0]=nums[0],dp数组的递推公式为 dp[i] = max( dp[i-1] + nums[i], nums[i] ),在遍历的时候从下标1开始,从数组的递推公式看出:连续的整数组成子数组中较大值是dp[i-1]+nums[i]或者nums[i]。

如果是其他类型的动态规划,取的值可能就是dp[i-1]+nums[i]或者dp[i-1],很容易出错。遍历完成之后,找出dp数组中的最大值。代码如下:

class Solution 
{
public:
    int maxSubArray(vector<int>& nums) {
        if(nums.size()==1)return nums[0];
        vector<int>dp(nums.size());
        dp[0]=nums[0];
        for(int i=1; i<nums.size(); i++)
        {
            dp[i]=max(nums[i],dp[i-1]+nums[i]);
        }
        return *max_element(dp.begin(),dp.end());
    }
};
方法二

方法二把方法一的dp数组压缩成一个数,空间复杂度是O(1),

从dp[i] = max ( nums[i], dp[i-1]+nums[i] )看出dp数组的每个元素只访问了一次,存在空间浪费,换句话说是当前dp数组的状态只和它前一个dp数组的状态有关系,和其他的dp数组元素无关,所以可以压缩。由于压缩会导致无法记录遍历过程中的最大子数组之和,所以还需要一个maxAns记录每一次遍历的最大值。代码如下:

class Solution 
{
public:
    int maxSubArray(vector<int>& nums) {
        int pre=nums[0],maxAns=nums[0];
        for(int i=1;i<nums.size();i++){
            pre=max(nums[i],pre+nums[i]);
            maxAns=max(maxAns,pre);
        }
        return maxAns;
    }
};