LeetCode | Maximum Product Subarray
来源:互联网 发布:数据化人生 好看吗 编辑:程序博客网 时间:2024/06/14 07:49
Find the contiguous subarray within an array (containing at least one number) which has the largest product.
For example, given the array [2,3,-2,4],
the contiguous subarray [2,3] has the largest product = 6.
这道题应当算是第一个独立做出来的DP了~撒花
经历了MLE、TLE和各种WA,终于找到了几乎是最优的解答方式(和Gas Station有点类似)
首先考虑这是一个DP问题。
因为首先,一个区间的最大值可以归结为其子区间的最大值问题,当前做了决策之后对后续不会产生影响(后续可以利用当前计算的结果)
一开始想是dp[i][j]与dp[i+1][j-1]之间的关系,随后想到如何处理负数的问题。
于是开启两个dp数组,一个存最大一个存最小,判断最大的时候也需要判断最小*当前值【因为有可能出现负的】
于是一开始写出的类似
dp1[i][j]=max{dp1[i+1][j-]*nums[j],dp2[i+1][j-1]}
随后问题来了,为何元素的扩展状态是2个方向??
之前回文问题可以这么做是因为回文要求两端相等,而这个问题则需要仔细考虑。
于是写出:
利用dp[i][j]记录从i~j位置乘积的最大值(正数)
dp[i][j]=max{dp[i][j-1]*nums[j],nums[j]}
意思也就是,第j位的元素等于前i~j-1位乘积最大值乘以当前值,如果比当前值大,就更新dp[i][j],否则就继续从j开始计算,dp[i][j]更新为nums[j]
如果遇到负数,那么这个数在将来有可能成为最大的数,所以负数需要额外开辟一个dp数组,专门用于存储最小值,这些最小值(负数)是“有潜力”成为最大值的数。
所以dp方程相应变为
dp[i][j]=max{dp[i][j-1]*nums[j],nums[j],dp2[i][j-1]*nums[j]}
dp2[i][j]=min{dp[i][j-1]*nums[j],nums[j],dp2[i][j-1]*nums[j]}
到这里终于正确了,不过一运行MLE。。。说明空间申请了太多了,看用例是给了一个大数组,这样n*n肯定是要爆掉的。
于是考虑可能并不需要数组就可以记录?
可以看到dp方程里面,i的值始终未变化,而产生变化的只有j。这说明dp[i][j]并不依赖于i点的状态,而是依赖于j-1点的状态。
所以直接考虑的是每次遍历的时候拿一个maxx和minn分别记录从i到当前位置的最大值。
因为原循环中也仅仅是利用了历史状态,记忆化搜索而已,但这些搜索的结果我们并不是完全都要,只要记录之前记录到的最大值并对它进行更新就好了
// for(int i=0;i<n;i++){ // int maxx=0,minn=0; // for(int j=i;j<n;j++){ int maxv=maxx,minv=minn; maxx=maxNum(maxv*nums[j],nums[j],minv*nums[j]); minn=minNum(maxv*nums[j],nums[j],minv*nums[j]); }}
这样确实直接省了2个数组,时间复杂度还是O(n^2) 但是空间复杂度由O(n^2)降到了O(1);
very nice;
跑一遍,TLE。。。
说明了什么,说明了二重循环也是没有必要的…
仔细想想,在i=0的时候,其实已经计算了从0开始,到n-1的最大值。
那为何还要计算从非第一个起点开始的呢?不还是遍历整个数组吗?
以此为启发,想到删除里层循环,只保留一个maxx和minn以及记录中间结果的val。
一次遍历,即可解决
class Solution {public: int maxProduct(vector<int>& nums) { int n=nums.size(); if(n==1) return nums[0]; //选取第i位为结尾的子串作为最大值 // vector<int> dp1(n,0); // vector<int> dp2(n,0); // int val=INT_MIN; // for(int i=0;i<n;i++){ // dp1[i]=maxNum(dp1[i-1]*nums[i],nums[i],dp2[i-1]*nums[i]); // dp2[i]=minNum(dp1[i-1]*nums[i],nums[i],dp2[i-1]*nums[i]); // } // for(int i=0;i<n;i++) // if(dp1[i]>val) val=dp1[i]; //如果是以i开始j结束为标记,需要n*n大小的标记 // vector<vector<int> > dp1; // vector<vector<int> > dp2; // dp1.resize(n,vector<int>(n)); // dp2.resize(n,vector<int>(n)); // for(int i=0;i<n;i++){ // for(int j=0;j<n;j++){ // dp1[i][j]=dp2[i][j]=0; // } // } //最优解法 int val=nums[0],maxx=nums[0],minn=nums[0]; for(int j=1;j<n;j++){ int maxv=maxx,minv=minn; maxx=maxNum(maxv*nums[j],nums[j],minv*nums[j]); minn=minNum(maxv*nums[j],nums[j],minv*nums[j]); val=maxx>val?maxx:val; } // int val=INT_MIN; // for(int i=0;i<n;i++){ // int maxx=0,minn=0; // for(int j=i;j<n;j++){ // //超时 // int maxv=maxx,minv=minn; // maxx=maxNum(maxv*nums[j],nums[j],minv*nums[j]); // minn=minNum(maxv*nums[j],nums[j],minv*nums[j]); // // 超内存 // 记录每一行每一列的的dp[i][j]表示以i开头j结尾的子串的乘积 // // dp1[i][j]=maxNum(dp1[i][j-1]*nums[j],nums[j],dp2[i][j-1]*nums[j]); // // dp2[i][j]=minNum(dp1[i][j-1]*nums[j],nums[j],dp2[i][j-1]*nums[j]); // val=maxx>val?maxx:val; // // if(nums[i] * nums[j]>0){ // // //这种模拟最长公共子序列的有可能是不连续的 // // dp1[i][j]=dp1[i+1][j-1]*nums[i]*nums[j]; // // dp2[i][j]=dp2[i+1][j-1]*nums[i]*nums[j]; // // } // // else if(nums[i] * nums[j]<0){ // // dp1[i][j]=max(dp1[i+1][j-1]*nums[i],dp2[i+1][j-1]*nums[j]); // // dp2[i][j]=min(dp1[i+1][j-1]*nums[j],dp2[i+1][j-1]*nums[i]); // // } // // else if(nums[i]<0 && nums[j]>0){ // // dp1[i][j]=max(dp2[i+1][j-1]*nums[i],dp1[i+1][j-1]*nums[j]); // // dp2[i][j]=min(dp2[i+1][j-1]*nums[j],dp1[i+1][j-1]*nums[i]); // // } // // else if(nums[i]*nums[j]==0){ // // } // } // } // output(dp1); return val; // return getMax(dp1); } int maxNum(int a,int b,int c){ int val=a>b?a:b; return val>c?val:c; } int minNum(int a,int b,int c){ int val=a<b?a:b; return val<c?val:c; } int getMax(vector<vector<int>> &result){ int val=INT_MIN; for(int i=0;i<result.size();i++){ for(int j=0;j<result[0].size();j++){ if(result[i][j]>val) val=result[i][j]; } } return val; } void output(vector<vector<int>> &result){ for(int i=0;i<result.size();i++){ for(int j=0;j<result[i].size();j++){ printf("%d ",result[i][j]); } printf("\n"); } }};
- Maximum Product Subarray 【LeetCode】
- [LeetCode] Maximum Product Subarray
- leetcode-Maximum Product Subarray
- Maximum Product Subarray -- LeetCode
- LeetCode-Maximum Product Subarray
- [LeetCode]Maximum Product Subarray
- [LeetCode]Maximum Product Subarray
- 【LeetCode】Maximum Product Subarray
- leetcode:Maximum Product Subarray
- leetcode: Maximum Product Subarray
- Leetcode: Maximum Product Subarray
- [LeetCode]Maximum Product Subarray
- Leetcode Maximum Product Subarray
- [Leetcode]Maximum Product Subarray
- Leetcode--Maximum Product Subarray
- Maximum Product Subarray [leetcode]
- LeetCode | Maximum Product Subarray
- LeetCode-Maximum Product Subarray
- 数据结构学习笔记之栈结构
- 三维视觉传感器的类型
- C#不用ArcEngine,生成Shp文件(四)---------生成.dbf文件
- (十六)maven实践-如何查找和使用插件
- tomcat内存溢出解决办法
- LeetCode | Maximum Product Subarray
- R语言统计用函数归类
- maven初用回味
- openWRT摄像头选购
- spring+freemarker生成word 文档
- SEED-510PLUS仿真器驱动在CCS5.1下安装
- Python爬虫入门(8):Beautiful Soup的用法
- IDEA 部署web项目
- 简单工厂模式