【算法】【动规】乘积为正数的最长子数组长度


跳转汇总链接

👉🔗算法题汇总链接


1.1 乘积为正数的最长子数组长度

🔗题目链接

给你一个整数数组 nums ,请你求出乘积为正数的最长子数组的长度。
一个数组的子数组是由原数组中零个或者更多个连续数字组成的数组。
请你返回乘积为正数的最长子数组长度。

在写代码前,务必先做好这五步!梳理清楚思路,写代码只是顺手的事儿,这是第一道题,所以会详细描述分析方法,后面的题也是同一个流程~

  1. 状态表示
    • 本题得需要两个 dp 表,这里做 f 表和 g 表(设两个表不是一开始就能看出来的,是分析后得出的。先按照题意设一个记录乘积为正数的的最长子数组的长度 f 表,后面在分析正负数情况的时候发现还需要一个记录负数的,于是增添了 g 表)
    • f[i] 表示:以 i 位置元素为结尾乘积为正数的最长子数组的长度
    • g[i] 表示:以 i 位置元素为结尾乘积为负数的最长子数组的长度
  2. 状态转移方程在这里插入图片描述
    • 分析 f:首先将“子数组乘积为正数”中的“子数组”,分为自身和自身+之前的解,按照题意分为长度为1或者长度大于1,可以分析状态转移方程(如下) 在这里插入图片描述
      • 原本需要分成这两类,是因为一般会取 max(自身,自身+之前的解) 或是 min(自身,自身+之前的解),但是这道题我们可以观察到,列出来的方程中 nums[i] 符号相同时的情况可以覆盖另一个,所以方程可以简单写成如下。
        在这里插入图片描述
    • g 表的分析同理。
      在这里插入图片描述
  3. 初始化
    • 涉及到 -1 的位置可能在填表的时候越界,这里选用在表的首部多加一个空格的方式防止越界,初始化内容为 0,不会影响后续表的填写。
  4. 填表顺序
    • 从左往右,两张表一起填。
  5. 返回值
    • f 表里的最大值。

🐎代码如下:

class Solution {
public:
    int getMaxLen(vector<int>& nums) {
		// 1. 创建 dp 表
        int n = nums.size();
        vector<int> f(n + 1);   // 乘积为正数的最长数
        auto g = f;             // 乘积为负数的最长数
        
        // 2. 初始化
        int fmax = 0;
        f[0] = g[0] = 0;
        
        // 3. 誊写状态转移方式
        for(int i = 1; i < n + 1; i++)
        {
            if(nums[i - 1] > 0)
            {
                f[i] = f[i-1] + 1;
                g[i] = g[i-1] == 0 ? 0 : g[i-1] + 1;
            }
            else if(nums[i - 1] < 0)
            {
                f[i] = g[i-1] == 0 ? 0 : g[i-1] + 1;
                g[i] = f[i-1] + 1;
            }
            fmax = max(fmax, f[i]);
        }
        
        // 4. 返回值
        return fmax;
    }
};

🥰如果本文对你有些帮助,欢迎👉 点赞 收藏 关注,你的支持是对作者大大莫大的鼓励!!(✿◡‿◡) 若有差错恳请留言指正~~


  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值