68 lines
2.7 KiB
Java
Raw Normal View History

2025-04-17 12:08:47 +08:00
package dynamic_programming;
/**
* 题目 152. 乘积最大子数组 (MaxProduct)
* 描述给你一个整数数组 nums 请你找出数组中乘积最大的非空连续 子数组该子数组中至少包含一个数字并返回该子数组所对应的乘积
* 测试用例的答案是一个 32- 整数
* 示例 1
输入: nums = [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6
* 链接https://leetcode.cn/problems/maximum-product-subarray/
*/
//不会
2025-07-25 18:23:29 +08:00
//二刷不会
2025-04-17 12:08:47 +08:00
public class MaxProduct {
2025-07-25 18:23:29 +08:00
/**
* 用动态规划维护遍历到当前位置时 nums[i] 结尾的最大乘积最小乘积
* - prevMax前一步的最大乘积
* - prevMin前一步的最小乘积因为负数相乘会翻转大小
* 对于新元素 x = nums[i]候选值只有三种
* 1. 单独以 x 为一段子数组
* 2. x prevMax 相乘延续最大乘积序列
* 3. x prevMin 相乘延续最小乘积序列有可能翻转成最大
* 因此通过 max(x, x*prevMax, x*prevMin) 得到新的 currMax
* 同理用 min(x, x*prevMax, x*prevMin) 得到 currMin
* 然后更新全局答案 ans = max(ans, currMax)
*/
2025-04-17 12:08:47 +08:00
public int maxProduct(int[] nums) {
if (nums == null || nums.length == 0) {
throw new IllegalArgumentException("数组不能为空");
}
// 初始化:第 0 个位置的最大/最小乘积都等于 nums[0]
int prevMax = nums[0];
int prevMin = nums[0];
int ans = nums[0];
// 从 i=1 开始遍历
for (int i = 1; i < nums.length; i++) {
int x = nums[i];
// 三个候选值x、x*prevMax、x*prevMin
int candidateMax = Math.max(x, Math.max(x * prevMax, x * prevMin));
int candidateMin = Math.min(x, Math.min(x * prevMax, x * prevMin));
// 更新当前的最大/最小乘积
prevMax = candidateMax;
prevMin = candidateMin;
// 更新全局答案
ans = Math.max(ans, prevMax);
}
return ans;
}
// 简单测试
public static void main(String[] args) {
MaxProduct sol = new MaxProduct();
System.out.println(sol.maxProduct(new int[]{2, 3, -2, 4})); // 输出 6
System.out.println(sol.maxProduct(new int[]{-2, 0, -1})); // 输出 0
System.out.println(sol.maxProduct(new int[]{-2, 3, -4})); // 输出 24
System.out.println(sol.maxProduct(new int[]{-1, -3, -10, 0, 60})); // 输出 60
System.out.println(sol.maxProduct(new int[]{-2, -5, -2, -4, 3})); // 输出 240
}
}