乘积最大子序列

时间:2022-05-02 00:41:34
题目描述:找出一个序列中乘积最大的连续子序列(至少包含一个数)。

样例:比如, 序列 [2,3,-2,4] 中乘积最大的子序列为 [2,3] ,其乘积为6。


动态规划问题,用一个数组record记录每次运算的结果。这里面有个问题,就是求前n位的乘积最大子序列的最大乘积时,的确和前n - 1位有关,但是不一定和前n - 1位的乘积最大子序列的乘积有关,他有可能是由乘积最小子序列得到的,甚至和最大最小的乘积都没有关系。

比如,看下面的子序列:

1. [2, -3, -5],前3位的乘积最大子序列为2 * -3 * -5 = 30。而前2位的乘积最大子序列为2,乘积最小子序列的值为2 * 3 = -6,可见与乘积最小的子序列是有关系的

2. [-3 , 6],前2位的乘积最大子序列与前1位没有关系,是最后一位本身。


总结一下,也就是说,前 n 位的乘积最大子序列分以下3种情况:

1. 前n - 1位的乘积最小子序列的乘积 * A[n]最大

2. 前n - 1位的乘积最大子序列的乘积 * A[n]最大

3. 前n - 1位的乘积最大子序列和乘积最小子序列的乘积 * A[n]都不是最大,而A[n]本身最大。


状态转移方程:f_max(n) = max(f_max(n - 1) * A[n], f_min(n - 1) * A[n], A[n]),其中,f_max(n)表示到原数组第n位时,乘积最大子序列的乘积,f_min(n)表示到原数组第n位时,乘积最小子序列的乘积

所以,方便起见,将记录计算结果的数组record的每个元素写成一个二元组,记录到此时,前面的数组的最大乘积和最小乘积子序列的乘积。record[i][0]表示最小值,record[i][1]表示最大值。


代码如下:

class Solution:
    # @param nums: an integer[]
    # @return: an integer
    def maxProduct(self, nums):
        n = len(nums)
        if n == 0:
            return None
        # 每一次运算记录最大值和最小值,最小值放在第一位,最大值放在第二位
        record = [[0, 0] for i in range(n)]
        # 初始化第一个记录
        record[0][0], record[0][1] = nums[0], nums[0]
        max_value = nums[0]
        # 从第二个元素开始计算
        index = 1
        while index < n:
            # 一个可能的最值(最大最小不知)
            t1 = record[index - 1][0] * nums[index]
            # 另一个可能的最值(最大最小不知)
            t2 = record[index - 1][1] * nums[index]
            # 最小值
            record[index][0] = min(nums[index], t1, t2)
            # 最大值
            record[index][1] = max(nums[index], t1, t2)
            # 最大值比较函数
            max_value = max(record[index][1], max_value)
            index += 1
        return max_value
        # write your code here