【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_dp、nums[i] * min_dp 三个数去求新的最大值和最小值,代码写起来非常繁琐。

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

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

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


💻 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;
    }
};
相关推荐
郑同学的笔记3 小时前
【c++随笔28】strcmp 和 memcmp对比
开发语言·c++
随意起个昵称3 小时前
【背包dp】输出方案路径
c++·动态规划
朝朝辞暮i4 小时前
C++ 第 27 课:智能指针 shared_ptr
开发语言·c++·算法
by209994 小时前
学会使用std::string类,并理解其内部是如何管理字符串的详细阐述(上)
c++·笔记·字符串·类和对象·string
沙漠之主4 小时前
C++编程教学设计资料:从入门到实战的完整课程方案
java·前端·c++
朝朝辞暮i5 小时前
C++ 第 29 课:回调函数 Callback
开发语言·c++·算法
kaixin_learn_qt_ing5 小时前
C++多态实现原理
c++
无名猿5 小时前
unique_ptr 完全指南:独占所有权与零开销
c++·性能优化·内存管理·标准库·现代c++
笑鸿的学习笔记5 小时前
C++笔记之大块顺序写
java·c++·笔记
Navigator_Z5 小时前
LeetCode //C - 1278. Palindrome Partitioning III
c语言·算法·leetcode