一句话说透数据结构里面的给定数组中的乘积最大子数组

154 阅读2分钟

一句话总结:
找乘积最大子数组就像炒股——既要抓住暴涨,也要警惕暴跌(负数可能负负得正),还要记得及时止损(遇到零重置)!


一、动态规划解法(最优解)

核心思路:  同时维护当前最大值和最小值(因为负数可能翻转局面)

Kotlin 代码:

fun maxProduct(nums: IntArray): Int {
    if (nums.isEmpty()) return 0
    
    var maxSoFar = nums[0]   // 全局最大值
    var currentMax = nums[0] // 当前最大值
    var currentMin = nums[0] // 当前最小值(应对负数)
    
    for (i in 1 until nums.size) {
        val num = nums[i]
        // 计算新的候选值(考虑三种情况:当前数、当前数×旧最大、当前数×旧最小)
        val candidates = listOf(num, currentMax * num, currentMin * num)
        currentMax = candidates.maxOrNull()!!
        currentMin = candidates.minOrNull()!!
        
        // 更新全局最大值
        maxSoFar = maxOf(maxSoFar, currentMax)
    }
    
    return maxSoFar
}

时间复杂度:  O(n) (只遍历一次数组)
空间复杂度:  O(1) (仅用几个变量存储状态)


二、测试用例

fun main() {
    println(maxProduct(intArrayOf(2, 3, -2, 4)))     // 输出6(子数组[2,3])
    println(maxProduct(intArrayOf(-2, 0, -1)))       // 输出0(子数组[0])
    println(maxProduct(intArrayOf(-3, -1, -2)))      // 输出6(子数组[-3,-1,-2])
    println(maxProduct(intArrayOf(0, 2)))            // 输出2(子数组[2])
    println(maxProduct(intArrayOf(-2, 3, -4)))       // 输出24(子数组[-2,3,-4])
}

三、分步图解(以数组[-2,3,-4]为例)

初始状态:
currentMax = -2, currentMin = -2, maxSoFar = -2

第1步(num=3):
候选值:3, (-2)*3=-6, (-2)*3=-6 → currentMax=3, currentMin=-6
maxSoFar更新为3

第2步(num=-4):
候选值:-4, 3*(-4)=-12, (-6)*(-4)=24 → currentMax=24, currentMin=-12
maxSoFar更新为24
最终结果:24

四、关键点解析

  1. 负数反转:遇到负数时,之前的最大值可能变最小值,最小值可能变最大值
  2. 零的处理:遇到零时,当前最大值和最小值都重置为零
  3. 候选值比较:每次必须同时考虑三种可能性(当前数、当前数×旧最大、当前数×旧最小)

五、常见错误

  1. 忽略最小值:只维护最大值会导致负数反转情况丢失

    // 错误示例(只跟踪最大值)
    fun wrongMaxProduct(nums: IntArray): Int {
        var maxSoFar = nums[0]
        var currentMax = nums[0]
        for (i in 1 until nums.size) {
            currentMax = maxOf(nums[i], currentMax * nums[i])
            maxSoFar = maxOf(maxSoFar, currentMax)
        }
        return maxSoFar
    }
    // 测试用例 [-2,3,-4] 会错误返回3,正确应为24
    
  2. 未处理空数组:需检查输入是否为空


六、适用场景

  • 股票最大收益计算(考虑价格波动)
  • 信号处理中的最大能量区间
  • 游戏中的连续增益效果计算

口诀:
最大乘积子数组,
动态规划双维护。
最大最小两手抓,
负数反转别马虎!