【Hot 100 刷题计划】 LeetCode 152. 乘积最大子数组 | C++ 动态规划 (绝妙 swap 翻转技巧)

LeetCode 152. 乘积最大子数组

📌 题目描述

题目级别:中等

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

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

  • 示例 1:

    输入: nums = [2,3,-2,4]

    输出: 6

    解释: 子数组 [2,3] 有最大乘积 6

  • 示例 2:

    输入: nums = [-2,0,-1]

    输出: 0

    解释: 结果不能为 2, 因为 [-2,-1] 不是子数组(不连续)。


💡 破题思路:动态规划的"负负得正"陷阱

这道题和"最大子数组和"非常像,但乘法有一个致命的特殊性:负号的存在

一个极其小的负数,如果再乘上一个负数,会瞬间翻盘变成一个巨大的正数!

因此,我们不能只记录"当前的最大乘积",我们还必须同时记录"当前的最小乘积"(因为它有潜力在遇到下一个负数时变身成最大乘积)。

本解法的极客高光点 (Swap 魔法):

常规思路是在每次遍历时,同时用 nums[i]nums[i] * max_dpnums[i] * min_dp 三个数去求新的最大值和最小值,代码写起来非常繁琐。

但我们回归数学本质:当遇到一个负数时,乘积的大小关系会发生反转

所以,如果我们发现当前数字 nums[i] < 0,我们直接把维护的"当前最大值 mam"和"当前最小值 mim"互换位置 (swap)

互换之后,我们就可以像处理正数一样,毫无顾忌地直接更新 mammim 了。这个思路极其优雅,堪称神来之笔。


💻 C++ 代码实现 (O(1) 空间极简版)

cpp 复制代码
class Solution {
public:
    int maxProduct(vector<int>& nums) {
        // mim 维护以当前元素结尾的最小乘积
        // mam 维护以当前元素结尾的最大乘积
        int mim = 1, mam = 1; 
        int res = INT_MIN; // 全局最大结果

        for (int i = 0; i < nums.size(); i ++ )
        {
            // 绝妙逻辑:遇到负数,乘积的极值属性反转,直接 swap!
            if (nums[i] < 0)
            {
                swap(mim, mam);
            }

            // 要么是从前面连乘过来的,要么就是从当前元素重新开始自己单干
            mim = min(nums[i], mim * nums[i]);
            mam = max(nums[i], mam * nums[i]);

            // 每次更新全局最大值
            res = max(res, mam);
        }

        return res;
    }
};
相关推荐
NiceCloud喜云3 小时前
Opus 4.8 的 Effort Control 怎么选:Low 到 Max 五档策略
android·java·大数据·前端·c++·python·spring
小羊在睡觉3 小时前
力扣84. 柱状图中最大的矩形
后端·算法·leetcode·golang·go
cjhbachelor3 小时前
c++继承
c++
肩上风骋3 小时前
C++14特性
开发语言·c++·c++14特性
sheeta19984 小时前
LeetCode 每日一题笔记 日期:2026.05.29 题目:3300. 最小元素
笔记·leetcode
_日拱一卒4 小时前
LeetCode:994腐烂的橘子
java·数据结构·算法·leetcode·深度优先
QiLinkOS6 小时前
【从实验室到商业战场:发明专利如何重塑科技与企业的共生生态】
大数据·c语言·数据结构·c++·人工智能·单片机·算法
Irissgwe7 小时前
c++11(lambda表达式与包装器、线程库)
c++·c++11·lambda表达式·线程库·包装器·互斥量库·条件变量库
小白兔奶糖ovo7 小时前
【Leetcode】231. 2的幂
linux·算法·leetcode
Peter·Pan爱编程7 小时前
14. Lambda 表达式:随手可写的函数对象
c++·算法·ai编程