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

【LeetCode热题100道笔记+动画】乘积最大子数组

题目描述

给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续 子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

测试用例的答案是一个 32-位 整数。

示例 1:
输入: nums = [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。

示例 2:
输入: nums = [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。

提示:

  • 1<=nums.length<=2∗1041 <= nums.length <= 2 * 10^41<=nums.length<=2104
  • −10<=nums[i]<=10-10 <= nums[i] <= 1010<=nums[i]<=10
  • nums 的任何子数组的乘积都 保证 是一个 32-位 整数

思考

针对含负数的数组,最大乘积子数组需同时追踪“最大乘积”和“最小乘积”:

  • 负数特性导致:最小乘积(可能为负)× 负数 可能变为最大乘积
  • 用动态规划维护两个状态数组,分别记录以每个位置结尾的最大/最小乘积

算法过程

  1. 初始化

    • dpMax[i]:以第i个元素结尾的子数组的最大乘积
    • dpMin[i]:以第i个元素结尾的子数组的最小乘积
    • 初始值:dpMax[0] = dpMin[0] = nums[0](首个元素自身构成子数组)
    • 结果变量result初始化为nums[0]
  2. 遍历更新(i从1到n-1)

    • 计算当前位置的最大乘积:dpMax[i] = max(dpMax[i-1]×nums[i], dpMin[i-1]×nums[i], nums[i])
    • 计算当前位置的最小乘积:dpMin[i] = min(dpMin[i-1]×nums[i], dpMax[i-1]×nums[i], nums[i])
    • 更新全局结果:result = max(result, dpMax[i])
  3. 返回结果:最终result即为最大乘积子数组的乘积

时间复杂度

  • 时间复杂度:O(n),仅遍历数组一次(n为数组长度)
  • 空间复杂度:O(n),使用两个长度为n的状态数组(可优化为O(1),只需保留前一位置的最大/最小值)

该方法通过同时追踪最大和最小乘积,完整覆盖了负数带来的乘积反转情况,确保找到全局最大乘积。

代码一

/*** @param {number[]} nums* @return {number}*/
var maxProduct = function(nums) {const n = nums.length;const dpMax = Array(n).fill(-Infinity);const dpMin = Array(n).fill(-Infinity);dpMax[0] = nums[0];dpMin[0] = nums[0];let result = nums[0];    for (let i = 1; i < n; i++) {dpMax[i] = Math.max(dpMax[i-1] * nums[i], dpMin[i-1] * nums[i], nums[i]);dpMin[i] = Math.min(dpMin[i-1] * nums[i], dpMax[i-1] * nums[i], nums[i]);result = Math.max(dpMax[i], dpMin[i], result);}return result;
};

代码二:优化O(1)空间

/*** @param {number[]} nums* @return {number}*/
var maxProduct = function(nums) {const n = nums.length;let preMax = nums[0], preMin = nums[0], result = nums[0];    for (let i = 1; i < n; i++) {let curMax = Math.max(preMax * nums[i], preMin * nums[i], nums[i]);let curMin = Math.min(preMax * nums[i], preMin * nums[i], nums[i]);result = Math.max(curMax, curMin, result);preMax = curMax;preMin = curMin;}return result;
};

可视化

在这里插入图片描述

http://www.xdnf.cn/news/1417645.html

相关文章:

  • AI+PLM如何重构特种/高端复杂装备行业的工艺管理?
  • 再见 K8s!3款开源的云原生部署工具
  • 开源模型应用落地-模型上下文协议(MCP)-为AI智能体打造的“万能转接头”-“mcp-use”(十二)
  • [开源项目] Tiny-RAG :一套功能完善、高度可配的本地知识库问答解决方案
  • 深度学习篇---ShuffleNet网络结构
  • 广电手机卡到底好不好?
  • 科学研究系统性思维的方法体系:数据收集
  • 【Audio】切换至静音或振动模式时媒体音自动置 0
  • docker安装redis,进入命令窗口基操练习命令
  • 优化括号匹配检查:从Stack到计数器的性能提升
  • MOS管学习
  • Linux 进程状态 — 僵尸进程
  • FDTD_梯度波导学习(1)
  • HOW - 前端团队产出评定方案参考
  • 携程旅行 web 验证码 分析
  • JavaEE 进阶第一期:开启前端入门之旅(上)
  • GitLab 18.3 正式发布,更新多项 DevOps、CI/CD 功能【二】
  • 餐饮门店的小程序怎么做?如何开发餐饮店下单小程序?
  • C++11模板优化大揭秘:让你的代码更简洁、更安全、更高效
  • CICD实战(2) - 使用Arbess+GitLab+SonarQube实现Java项目快速扫描/构建/部署
  • 简单实现Ai音乐suno-api
  • TCP粘包
  • 考研复习-计算机网络-第一章-计算机网络概述
  • keil MDK如何使用第三方软件Keil2Json.exe生成compile_commands.json文件,方便vscode+clangd环境使用
  • 深度解析条件编译:#ifdef与#ifndef的本质区别与应用实践
  • [Android] 京墨 v1.15.2 —— 古诗词文、汉语字典、黄历等查询阅读学习宝典(可离线)
  • MTK-Android13-实现拷贝预置资源到vendor分区下
  • Scikit-learn Python机器学习 - 字典特征提取-DictVectorizer
  • 电脑没加域却能获取到IP地址
  • 基于单片机宠物项圈/宠物防丢失设计