Similar idea from 53. Maximum Subarray, but the difference is that the product of two negative numbers is positive. A very negative product can be very positive if multiplied by another negative later.
So we store the local maximum and minimum simultaneously during iteration. There are three ways to calculate a subarray product ending at i:
- Fresh start at
nums[i]. - Extend previous max with
nums[i]:localMax[i - 1] * nums[i]. - Extend previous min with
nums[i]:localMin[i - 1] * nums[i].
-3, 2, -4
localMax -3 2 * = max(-4, 2 * -4, -6 * -4) = 24
localMin -3 -6 * = min(-4, 2 * -4, -6 * -4) = -8
globalMax -3 2 * = max(2, 24) = 24
-2, 3, -4
localMax -2 3 * = max(-4, 3 * -4, -6 * -4) = 24
localMin -2 -6 * = min(-4, 3 * -4, -6 * -4) = -12
globalMax -2 3 * = max(3, 24) = 24fun maxProduct(nums: IntArray): Int {
val n = nums.size
if (n == 0) return 0
val localMax = IntArray(n) { Int.MIN_VALUE }
val localMin = IntArray(n) { Int.MAX_VALUE }
localMax[0] = nums.first()
localMin[0] = nums.first()
var globalMax = nums.first()
for (i in 1 until n) {
localMax[i] = maxOf(
nums[i],
nums[i] * localMax[i - 1],
nums[i] * localMin[i - 1]
)
localMin[i] = minOf(
nums[i],
nums[i] * localMax[i - 1],
nums[i] * localMin[i - 1],
)
globalMax = maxOf(globalMax, localMax[i])
}
return globalMax
}- Time Complexity:
O(n). - Space Complexity:
O(n).
fun maxProduct(nums: IntArray): Int {
val n = nums.size
if (n == 0) return 0
var previousMax = nums.first()
var previousMin = nums.first()
var globalMax = nums.first()
for (i in 1 until n) {
// We can't set `previousMax` here, see below WA.
val currentMax = maxOf(
nums[i],
nums[i] * previousMax,
nums[i] * previousMin
)
val currentMin = minOf(
nums[i],
nums[i] * previousMax,
nums[i] * previousMin
)
globalMax = maxOf(globalMax, currentMax)
previousMax = currentMax
previousMin = currentMin
}
return globalMax
}- Time Complexity:
O(n). - Space Complexity:
O(1).
We can't not overwrite the previousMax immediately, because we still need to use the actual previous max/min to calculate the current max/min.
fun maxProduct(nums: IntArray): Int {
val n = nums.size
if (n == 0) return 0
var previousMax = nums.first()
var previousMin = nums.first()
var globalMax = nums.first()
for (i in 1 until n) {
// We overwrite the previous max immediately in this iteration.
previousMax = maxOf(
nums[i],
nums[i] * previousMax,
nums[i] * previousMin
)
previousMin = minOf(
nums[i],
nums[i] * previousMax, // This has been updated from above, it's not the actual previous max, which leads to WA.
nums[i] * previousMin
)
globalMax = maxOf(globalMax, previousMax)
}
return globalMax
}
*/