持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第12天,点击查看活动详情
最近一直在力扣刷题,也逐渐对各类题型有了自己的理解,所谓见招拆招,将自己的浅显经验分享一下,帮助更多在编程路上的朋友们。
乘积最大的子数组
给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
示例 1:
输入: nums = [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例 2:
输入: nums = [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
思路
这是一个标准的动态规划题,状态转移方程也很简单:dp[i] = Math.max(dp[i - 1] * nums[i], nums[i]) ,每次保存当前状态下的最大值。
但是会有一个坑,乘法无非考虑正数、负数、零,如果有一个数组[-2, 3, 5,-4],数组两侧为负数,这种情况下乘积最大的应为120,但上述状态转移方程是无法处理这种情况的,故需要另外一个状态方程来保存负数的情况,即保存乘积最小的情况。
dpMax保存乘积最大值 dpMin保存乘积最小值
此时的最大乘积dpMax有三种情况:
- 前面乘积为正数,nums[i]为正数,最大值取dpMax[i - 1] * nums[i]
- 前面乘积为负数,nums[i]为负数,最大值取dpMin[i - 1] * nums[i]
- 前面乘积为零,最大值取nums[i]
最小乘积(负数)同理。
题解
class Solution {
public int maxProduct(int[] nums) {
int n = nums.length;
int dpMax = nums[0];
int dpMin = nums[0];
int max = nums[0];
for(int i = 1; i < n; i++) {
int t1 = dpMax, t2 = dpMin;
dpMax = Math.max(Math.max(nums[i], t1 * nums[i]), t2 * nums[i]);
dpMin = Math.min(Math.min(nums[i], t1 * nums[i]), t2 * nums[i]);
max = Math.max(max, dpMax);
}
return max;
}
}