力扣-152-乘积最大子数组
题目分析:按照最大子序列和的想法很容易写出转台转移方程:
$$dp_{max}\left [ i \right ]=max\left ( dp_{max}[i-1]\ast nums\left [ i \right ],nums\left [ i \right ] \right )$$
$dp_{max}\left[ i \right]$表示第$i$个元素结尾的乘积最大子数组的乘积。
乍一看是是对的,但是确有问题,因为忽略了乘法中负负得正的规则。比如$nums=\left \{ 5,6,-3,4,-3 \right \}$。
最后一个$-3$所对应的$dp_{max}$既不是$-3$,也不是$4*(-3)$,而是$5\times 6\times \left ( -3 \right )\times 4\times \left ( -3 \right )$
分类讨论,如果$nums[i]$是正数,那么希望他前一个位置结束的$dp_{max}$是一个正数,并且尽可能的大;反之,希望他前一个位置结束的$dp_{max}$是
一个负数,并且尽可能的小(负得多)。那么更改状态转移方程有:
$$dp_{max}\left [ i \right ]=max\left (dp_{max}[i-1]\ast nums\left [ i \right ], dp_{min}[i-1]\ast nums\left [ i \right ],nums\left [ i \right ] \right )$$
$$dp_{min}\left [ i \right ]=min\left (dp_{max}[i-1]\ast nums\left [ i \right ], dp_{min}[i-1]\ast nums\left [ i \right ],nums\left [ i \right ] \right )$$
#include <algorithm> using namespace std; class Solution { public: int maxProduct(vector<int>& nums) { int num = nums.size(); vector<int> dp_max(num), dp_min(num); dp_max[0] = nums[0]; dp_min[0] = nums[0]; for(int i = 1; i < num; i++) { dp_max[i] = max(dp_max[i - 1]*nums[i], max(dp_min[i - 1]*nums[i], nums[i])); dp_min[i] = min(dp_min[i - 1]*nums[i], min(dp_max[i - 1]*nums[i], nums[i])); } return *max_element(dp_max.begin(), dp_max.end()); } };
max_element(r, r+6),返回数组r中[0, 6)之间的最大值的迭代器,
使用max_element返回的值减去数组头地址即为该最大值在数组的序号。
为了减少空间复杂度,我们可以用滚动数组来做$dp$:
#include <algorithm> using namespace std; //使用滚动数组优化空间 class Solution { public: int maxProduct(vector<int>& nums) { int dp_max = nums[0], dp_min = nums[0], result = nums[0]; for(int i = 1; i < nums.size(); i++) { int dmax = dp_max, dmin = dp_min; dp_max = max(dmax * nums[i], max(dmin * nums[i], nums[i])); dp_min = min(dmin * nums[i], min(dmax * nums[i], nums[i])); result = max(result, dp_max); } return result; } };
作者:Ryanjie
出处:http://www.cnblogs.com/ryanjan/
本文版权归作者和博客园所有,欢迎转载。转载请在留言板处留言给我,且在文章标明原文链接,谢谢!
如果您觉得本篇博文对您有所收获,觉得我还算用心,请点击右下角的 [推荐],谢谢!