当前位置: 首页 > news >正文

LeetCode算法日记 - Day 84: 乘积为正数的最长子数组长度

目录

1. 乘积为正数的最长子数组长度

1.1 题目解析

1.2 解法

1.3 代码实现


1. 乘积为正数的最长子数组长度

https://leetcode.cn/problems/maximum-length-of-subarray-with-positive-product/description/

给你一个整数数组 nums ,请你求出乘积为正数的最长子数组的长度。

一个数组的子数组是由原数组中零个或者更多个连续数字组成的数组。

请你返回乘积为正数的最长子数组长度。

示例  1:

输入:nums = [1,-2,-3,4]
输出:4
解释:数组本身乘积就是正数,值为 24 。

示例 2:

输入:nums = [0,1,-2,-3,-4]
输出:3
解释:最长乘积为正数的子数组为 [1,-2,-3] ,乘积为 6 。
注意,我们不能把 0 也包括到子数组中,因为这样乘积为 0 ,不是正数。

示例 3:

输入:nums = [-1,-2,-3,0,1]
输出:2
解释:乘积为正数的最长子数组是 [-1,-2] 或者 [-2,-3] 。

提示:

  • 1 <= nums.length <= 10^5
  • -10^9 <= nums[i] <= 10^9

1.1 题目解析

题目本质
这是一道动态规划问题,核心是求「乘积为正数的最长连续子数组长度」。本质上是在处理符号变化:正数、负数、零对乘积符号的影响。

常规解法
最直观的想法是枚举所有子数组,计算每个子数组的乘积,判断是否为正,记录最长长度。代码如下:

for (int i = 0; i < n; i++) {long product = 1;for (int j = i; j < n; j++) {product *= nums[j];if (product > 0) {maxLen = Math.max(maxLen, j - i + 1);}}}

问题分析
这种暴力枚举的时间复杂度是 O(n²),对于 n ≤ 10⁵ 的数据规模会超时。更致命的是,我们并不关心乘积的具体值,只关心乘积的符号(正/负/零),每次都去计算乘积是一种浪费。

思路转折
关键观察:乘积的符号只取决于负数的个数

  • 负数个数为偶数 → 乘积为正

  • 负数个数为奇数 → 乘积为负

  • 遇到 0 → 乘积为 0,必须重新开始

要想高效 → 必须避免重复计算 → 动态规划登场。我们可以用两个状态:

  • f[i]:以 nums[i] 结尾的乘积为正的最长子数组长度

  • g[i]:以 nums[i] 结尾的乘积为负的最长子数组长度

要想高效 → 利用前面的计算结果 → 动态规划:维护两个状态来记录"以当前位置结尾的正数链"和"负数链"的长度,O(1) 完成状态转移,总复杂度降为 O(n)。

1.2 解法

算法思想

定义状态:

  • f[i] = 以第 i 个元素结尾的乘积为正的最长子数组长度

  • g[i] = 以第 i 个元素结尾的乘积为负的最长子数组长度

状态转移方程:

if(nums[i-1] > 0){if(g[i-1] == 0){g[i] = 0;f[i] = Math.max(1, f[i-1]+1);}else{f[i] = Math.max(1, f[i-1]+1);g[i] = Math.max(0, g[i-1]+1);}
}else if(nums[i-1] < 0){if(g[i-1] == 0){f[i] = 0;g[i] = Math.max(1, f[i-1]+1);}else{f[i] = Math.max(0, g[i-1]+1);g[i] = Math.max(1, f[i-1]+1);}
}else{f[i] = g[i] = 0;
}

i)初始化:创建两个 DP 数组 f 和 g,长度为 m+1(m 为数组长度),初始值 f[0] = 0, g[0] = 0,表示空数组状态

ii)遍历数组:从 i = 1 到 m,使用 nums[i-1] 访问当前元素,根据元素符号进行状态转移

iii)分类讨论:

  • 遇到正数:

    • f[i] 存正数连续最长值,如果前面有个乘积是正数的子数组(f[i-1]),那乘上当前这个正数,乘积还是正数,长度+1

    • g[i] 存负数连续最长值,如果前面有个乘积是负数的子数组(g[i-1]),那乘上当前这个正数,乘积还是负数,长度+1

      • 如果前一个数是0,g[i] <0 && g[i-1] == 0,那么相乘之后 g[i] 一定为0,所以此时
        g[i] = 0

    • 简单说就是:正数不改变符号,只让长度增加

  • 遇到负数:

    • f[i] 存正数连续最长值,如果前面有个乘积是负数的子数组(g[i-1]),那乘上当前这个负数,负负得正,乘积变正数了

      • 如果前一个数是0,f[i] <0 && g[i-1] == 0,那么相乘之后 g[i] 一定为0,所以此时
        f[i] = 0

    • g[i] 存负数连续最长值,如果前面有个乘积是正数的子数组(f[i-1]),那加上当前这个负数,正负得负,乘积变负数了

    • 简单说就是:负数会反转符号(正变负,负变正)

  • 遇到零:

    • 乘积直接变成 0,之前的计算全作废,从下一个数重新开始

iv)更新答案:每次状态转移后,用 f[i] 更新全局最大值 ret

易错点

  • 初始化错误:f[0] 和 g[0] 不能初始化为负无穷,应该是 0(表示空数组状态)

  • Math.max 滥用:不能写 Math.max(1, f[i-1]+1),这会导致即使 f[i-1] = 0 也强制返回 1,破坏了 DP 逻辑。正确做法是先判断 f[i-1] 是否为 0

  • 负数链的判断:当前元素为负数时,只有前面存在正数链(f[i-1] > 0)才能形成新的负数链,否则只能自己单独成链(长度为 1)

  • 零的处理:遇到 0 必须将 f[i] 和 g[i] 都置为 0,因为乘积为 0 不是正数,必须从下一个元素重新开始

1.3 代码实现

class Solution {public int getMaxLen(int[] nums) {int m = nums.length;int[] f = new int[m + 1];  // f[i]: 以 nums[i-1] 结尾的乘积为正的最长长度int[] g = new int[m + 1];  // g[i]: 以 nums[i-1] 结尾的乘积为负的最长长度// 初始化:空数组时两条链长度都是 0f[0] = 0;g[0] = 0;int ret = 0;for (int i = 1; i <= m; i++) {if (nums[i - 1] > 0) {// 当前元素为正数// f[i] 存储正数链:正数自己可以延长正数链f[i] = f[i - 1] + 1;// g[i] 存储负数链:正数可以延长负数链,但前提是之前存在负数链if (g[i - 1] > 0) {g[i] = g[i - 1] + 1;} else {// 之前不存在负数链,当前正数无法单独形成负数链g[i] = 0;}} else if (nums[i - 1] < 0) {// 当前元素为负数// f[i] 存储正数链:负数可以把之前的负数链变成正数链(负负得正)if (g[i - 1] > 0) {f[i] = g[i - 1] + 1;} else {// 之前不存在负数链,当前负数无法形成正数链f[i] = 0;}// g[i] 存储负数链:负数可以把之前的正数链变成负数链,或自己单独成链g[i] = f[i - 1] + 1;} else {// 当前元素为 0,乘积为 0 不是正数,两条链都断掉f[i] = 0;g[i] = 0;}// 更新全局最大值ret = Math.max(ret, f[i]);}return ret;}
}

复杂度分析

  • 时间复杂度:O(n),只需遍历数组一次,每次状态转移 O(1)

  • 空间复杂度:O(n),需要两个长度为 n+1 的 DP 数组

http://www.dtcms.com/a/529864.html

相关文章:

  • s001网站建设设计个人网站建设实训目的
  • 高端大气的广告公司名字seo关键词优化公司
  • pc网站转换成wapdw做网站环境配置
  • 江门网站建设方案外包做暖暖视频网站
  • 摄影行业网站论坛wordpress还是
  • 软文推广平台推荐:垂直领域精准触达,效果提升新路径
  • 数据库MySQL基础
  • 办网站租服务器大气网站源码
  • ps做图网站做loge的网站
  • wordpress主题样式优化软件
  • 公司怎么建网站做推广做电商网站的公司
  • 怎么用dw做带登陆的网站网站 建设ppt
  • 怎么做网站排版企云网站建设
  • 网站建设如何传视频国外优秀购物网站设计
  • 大丰城乡建设局网站wordpress底部黑色的版权修改
  • WPF之布局
  • AD9361通信平台--AGC 原理(二)
  • 网站制作费用入什么科目龙文国土局漳滨村新农村建设网站
  • 社交网站 设计wordpress设计笔记
  • C_OBJ#_INTCOL#坏块导致数据库无法open故障处理---惜分飞
  • 如何建设网站 知乎图书馆网站建设的意义
  • 网站综合营销方案企业营销策略分析论文
  • 企业建站公司哪里找认养农业app模式定制开发
  • 网站建设前端技术网站关键词优化排名怎么做
  • 两个男生如何做网站代理网页是干什么的
  • 做app模板网站有哪些内容南沙高端网站建设
  • 红酒公司的网站建设WordPress插件手动
  • Agentic RL: 大模型后训练 SFT、PPO和GRPO
  • 织梦城市门户网站模板廊坊优化外包
  • 有些网站做不了seo背景视频素材下载免费