动态规划:子数组问题

目录

53. 最大子数组和

1.状态表示

2.状态转移方程

3.初始化

4.返回值

918. 环形子数组的最大和

1.状态表示

2.状态转移方程

3.初始化

4.返回值

152. 乘积最大子数组

1.状态表示

2.状态转移方程

3.初始化

4.返回值



1.状态表示

dp[i]:表示以i位置为结尾最大子数组的和

2.状态转移方程

当dp[i-1] <= 0, nums[i] >= 0 时,dp[i] = dp[i-1] + nums[i]

当dp[i-1] >= 0, nums[i] >=0时,dp[i] = dp[i-1] + nums[i]

当dp[i-1] >= 0, nums[i] <= 0 时, dp[i] = dp[i-1] + nums[i]

当dp[i-1] <=0, nums[i] <= 0时, dp[i] = num[i]

综合上面四种情况 dp[i] = max(nums[i], dp[i] = dp[i-1] + nums[i]);

3.初始化

因为状态转移方程用到了i-1,所以需要初始化0位置

dp[0] = nums[0];

4.返回值

将dp数组中出现的最大值返回。

class Solution {
public:
    //dp[i] 表示以i位置为结尾子数组的最大和
    //dp[i] = max(nums[i],dp[i-1]+nums[i]);
    int maxSubArray(vector<int>& nums) 
    {
        int n = nums.size();
        vector<int> dp(n);
        dp[0] = nums[0];
        int ret = 0;
        ret = nums[0];
        for(int i = 1; i < n; i++)
        {
            dp[i] = max(nums[i],dp[i-1]+nums[i]);
            ret = max(ret,dp[i]);
        }
        return ret;
    }
};

918. 环形子数组的最大和

1.状态表示

dp[i]:表示以i位置为结尾最大子数组的和

2.状态转移方程

最大子数组无非就是两种情况

第一种就像第一道题一样,最大子数组时正常连续的。

第二种就是数组的头部和尾部各占一部分。

第一种情况的的化就是第一道题的做法。

第二种情况可以使用取反的方法,数组的总和是固定的,只需求出中间连续最小子数组,用数组的总和 - 连续最小的子数组 = 第二种情况的最大子数组和

f[i]表示最大连续子数组之和,g[i]表示最小连续子数组之和。

f[i] = max(num[i], f[i-1] + nums[i]);

g[i] = min(num[i], f[i-1] + nums[i]);

3.初始化

f[0] = g[0] = nums[0];

4.返回值

需要记录 f[i]出现的最大值fmax,和g[i]出现的最小值gmin

返回 max(fmax, sum - gmin);

但是有一个特殊情况数组的元素都为负数的时候 sum = gmin,这样会返回0,特殊处理一下。

sum == gmin ? fmax : max(fmax, sum - gmin);

class Solution {
public:
    int maxSubarraySumCircular(vector<int>& nums) 
    {
        int n = nums.size();
        vector<int> f(n);
        auto g = f;
        if(n == 1)
        {
            return nums[0];
        }

        f[0] = nums[0];
        g[0] = nums[0];
        int sum = nums[0];
        int fmax = INT_MIN, gmin = 400000;

        for(int i = 1; i < n; i++)
        {
            sum += nums[i];
            f[i] = max(nums[i], f[i-1] + nums[i]);
            g[i] = min(nums[i], g[i-1] + nums[i]);
            fmax = max(fmax, f[i]);
            gmin = min(gmin, g[i]);
        }

        return sum == gmin ? fmax : max(fmax, sum - gmin);
    }
};

152. 乘积最大子数组

1.状态表示

dp[i]:表示i位置结尾乘积最大和的子数字

2.状态转移方程

f[i]:表示i位置结尾乘积最大和的子数组

g[i]:表示i位置结尾乘积最小和的子数组

f[i-1] >=0, nums[i] >= 0, f[i] = f[i-1] * nums[i]

f[i-1] <= 0,nums[i] <=0, f[i] = g[i-1] * nums[i]

f[i-1] >=0, nums[i] <= 0, f[i] = nums[i]

f[i-1] <=0, nums[i] >= 0,f[i] = nums[i]

综上所诉f[i] = max(nums[i], f[i-1] * nums[i], g[i-1] * nums[i]);

              g[i] = min(nums[i], f[i-1] * nums[i], g[i-1] * nums[i]);

3.初始化

f[0] = g[0] = nums[0];

4.返回值

返回f[i]出现的最大值

class Solution {
public:
    
    int maxProduct(vector<int>& nums) 
    {
        int n = nums.size();
        vector<int> f(n), g(n);
        f[0] = g[0] = nums[0];
        int ret = f[0];
        for(int i = 1; i < n; i++)
        {
            f[i] = max(nums[i], max(f[i-1] * nums[i], g[i-1] * nums[i]));
            g[i] = min(nums[i], min(f[i-1] * nums[i], g[i-1] * nums[i]));
            ret = max(ret, f[i]);
        }

        return ret;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值