题目要求找出数组 nums 中乘积最大的连续子数组,最直接的办法是遍历整个数组,穷举以数组元素 nums[i] 为开头的所有连续子数组,通过比较所有连续子数组的乘积,找到最大值,并返回。
可是穷举所有子数组的乘积的过程中,存在很多重复计算。因此可以考虑使用动态规划的思想来优化算法。
知识点: 动态规划及其空间优化
1. 暴力遍历
这种方法通过穷举所有可能的结果,得到最大值。因此要对数组进行两次遍历,并假定数组首元素为乘积最大值 max 。
第一次遍历确定乘积子数组的开头元素 nums[i]
第二次遍历确定子数组的组成长度,子数组范围从开头元素 nums[i] 到 数组结尾 nums[nums.size() - 1] ,使用变量 multi 存储当前数组的乘积,并与最大值 max 比较。
class Solution {
public:
int maxProduct(vector<int>& nums) {
int max = nums[0];
for(int i = 0; i < nums.size(); i++)
{
int multi = 1;
for(int j = i; j < nums.size(); j++)
{
multi = multi * nums[j];
max = max < multi ? multi : max;
}
}
return max;
}
};
2. 动态规划
“动态规划问题一定会具备「最优子结构」,才能通过子问题的最值得到原问题的最值。”
那么本题的最优子结构是什么呢?什么时候子数组的乘积为最大?
2.1 定义子问题
本题的子问题是找到乘积最大的所有元素吗?
不是,因为题目要求的是数组,乘积最大的若干元素可能并不相邻,所以无法构成数组。
本题的子问题应该为以 nums[i] 为结尾的乘积最大子数组。
2.2 状态转移方程
动态规划的核心就是写出状态转移方程,并给出基础条件。
下面我们尝试根据题目要求写出状态转移方程。
什么时候以 nums[i] 为结尾的子数组的乘积为最大?
一个正数乘一个正数还是一个正数,一个正数乘一个负数就是一个负数,两个负数相乘是正数。我们无法确定 nums[i] 是正数、负数