【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;
    }
};
相关推荐
anew___7 小时前
蜂鸣器播放音乐——让 Arduino 唱出旋律
c++·stm32·单片机·嵌入式硬件·c
stolentime9 小时前
洛谷P10515 转圈题解
c++·算法·数学建模·贪心算法
tdtsmt10 小时前
穿戴硬件量产工艺实录:天地通电子智能手表主板 SMT 贴片案
c++
wzdark11 小时前
基于矩阵的动态规划路径问题性能优化4
线性代数·矩阵·动态规划
土司大王12 小时前
LeetCode hot100 回溯专题总结:Java 通用模板、决策树模型
java·算法·leetcode·决策树
m0_7345717613 小时前
深入理解C++ 析构函数<一>基本概念
开发语言·c++
t-think14 小时前
C++ string 类(上)—— string类初识与常用接口详解
开发语言·c++
a1879272183114 小时前
【算法】链表(二):链表上的双指针——变速、异链与定距,和一份路程账本
数据结构·算法·leetcode·链表·go·指针·环形链表
cpp_learners14 小时前
C++ 实现责任链模式(Chain of Responsibility):从一堆 if-else 到可插拔的处理管道
开发语言·c++·责任链模式