Description
給定一個整數陣列
nums,找出一個乘積最大的連續子陣列(至少包含一個元素),回傳其乘積。
Example:
Input: nums = [2,3,-2,4] Output: 6
Intuition#
負數乘以負數會變正數,所以必須同時追蹤當前的最大值和最小值。
- 不同於最大子陣列和,乘積的負號會翻轉大小關係
- 遇到負數時,當前最大值和最小值會互換
- 每步都要考慮三種可能:
nums[i]本身、curMax * nums[i]、curMin * nums[i]
Approaches#
1: Brute Force (Enumerate All Subarrays)#
- 概念: 枚舉所有子陣列的起點和終點,計算乘積並取最大值
- 時間複雜度:
O(n^2) - 空間複雜度:
O(1)
class Solution {
fun maxProduct(nums: IntArray): Int {
var result = nums[0]
for (i in nums.indices) {
var product = 1
for (j in i until nums.size) {
product *= nums[j]
result = maxOf(result, product)
}
}
return result
}
}⭐2: Track Min and Max#
- 概念: 同時維護以當前元素結尾的最大乘積和最小乘積,遇負數時交換
- 時間複雜度:
O(n) - 空間複雜度:
O(1)
class Solution {
fun maxProduct(nums: IntArray): Int {
var result = nums[0]
var curMax = 1
var curMin = 1
for (num in nums) {
val candidates = longArrayOf(num.toLong() * curMax, num.toLong() * curMin, num.toLong())
curMax = candidates.max().toInt()
curMin = candidates.min().toInt()
result = maxOf(result, curMax)
}
return result
}
}🔑 Takeaways#
- Pattern: 雙狀態 DP — 當正負性會影響結果時,需要同時追蹤最大和最小
- 關鍵技巧: 乘積問題中負數的處理:負 * 負 = 正,所以最小值可能在下一步變成最大值