题目:乘积最大子数组

确定状态:dp[ i ] 代表“以当前元素为结尾的最大/最小乘积是多少”

状态转移:(具体公式见下图)一开始的想法是——如果当前元素乘上dp数组的上一个元素之后,所得乘积比上一个还要小,那么就以当前元素为起点向后乘;反之,将所得乘积作为以当前元素(nums[ i ])为结尾的连续乘积存入dp数组

但是这会导致一个问题——如果原数组是 [ -2, 3, -4 ] 这种类型的话,期望结果是24(因为负负得正),但是上一个方法却会直接抛弃-2 * 3的结果,转而从 -4 开始重新计数,又因为此时已经到达了末尾,此时dp数组为 [-2, -6, -4 ] 所以最后会返回-2

上一种方法相当于只记录了最大正乘积,没有考虑到最小负乘积可能会与负数相乘,因此还需要定义一个dp数组,用于存放最小乘积

 1int maxProduct(vector<int>& nums)
 2{
 3    if(nums.size() == 1) return nums[0];
 4    std::vector<int> dp_max(nums.size(), 1), dp_min(nums.size(), 1);
 5    dp_max[0] = dp_min[0] = nums[0];
 6
 7    int res = nums[0];
 8    for(int i = 1; i < nums.size(); i++)
 9    {
10        int choice1 = dp_max[i -1] * nums[i];
11        int choice2 = dp_min[i -1] * nums[i];
12
13        dp_max[i] = std::max({nums[i], choice1, choice2});
14        dp_min[i] = std::min({nums[i], choice1, choice2});
15
16        res = res < dp_max[i] ? dp_max[i] : res;
17    }
18    return res;
19}