LeetCode算法学习之乘积最大子数组
完整代码实现
class Solution {public int maxProduct(int[] nums) {//动态 规划if(nums == null || nums.length == 0){return 0;}int currentMax = nums[0];int currentMin = nums[0];int maxProduct = nums[0];for(int i = 1;i<nums.length;i++){if (nums[i] < 0) {int temp = currentMax;currentMax = currentMin;currentMin = temp;}currentMax = Math.max(nums[i], currentMax * nums[i]);currentMin = Math.min(nums[i], currentMin * nums[i]);maxProduct = Math.max(maxProduct,currentMax);}return maxProduct;}
}解题思路:
1. 问题分析
我们需要找到一个连续子数组,使得其乘积是所有可能的连续子数组中最大的。由于数组中可能包含正数、负数和零,因此需要考虑以下情况:
正数:直接相乘会使乘积变大。
负数:可能通过“负负得正”使乘积变大。
零:会重置当前乘积为0。
2. 动态规划思路
为了高效解决这个问题,我们采用动态规划的方法,同时维护两个状态:
• currentMax:以当前元素结尾的子数组的最大乘积。
• currentMin:以当前元素结尾的子数组的最小乘积(因为负数可能在未来变成最大值)。
3. 算法步骤
1. 初始化:
currentMax 和 currentMin 初始化为数组的第一个元素 nums。
maxProduct 初始化为 nums,用于记录全局最大乘积。
2. 遍历数组:
对于每个元素 nums[i]:
如果当前元素是负数:
交换 currentMax 和 currentMin。因为负数会使得最大值和最小值互换(负负得正)。
更新 currentMax 和 currentMin:
currentMax 取 nums[i] 和 currentMax * nums[i] 中的较大值。
currentMin 取 nums[i] 和 currentMin * nums[i] 中的较小值。
更新全局最大值 maxProduct:
比较 maxProduct 和 currentMax,取较大者。
3. 返回结果:
遍历结束后,maxProduct 即为整个数组中乘积最大的连续子数组的乘积。
4. 关键点解释
为什么需要维护 currentMin?
因为负数乘以负数会变成正数,可能成为新的最大值。例如:
数组 [-2, 3, -4]:
到 -4 时,currentMin 是 -6(-2 * 3),-4 * -6 = 24 是新的最大值。
为什么遇到负数时要交换 currentMax 和 currentMin?
负数会反转大小关系。例如:
如果 currentMax = 5,currentMin = -2,遇到 -3:
不交换时:currentMax = max(-3, 5*-3) = -3(错误)。
交换后:currentMax = max(-3, -2*-3) = 6(正确)。
零的影响:
如果 nums[i] = 0,currentMax 和 currentMin 都会变成 0,相当于重置子数组。
