leetcode 152. 乘积最大子序列
暴力解法:O(n2)使用循环或者递归的方式求解,
我的C++代码:O(n),对于第i次计算,每次记录最大值与当前元素乘积,所有不为0的数到当前元素乘积,从第一个负数的后一个元素到当前元素的乘积,以及当前元素,从这四个可能的值里挑出最大的值即为以当前下标结尾的最大乘积的连续子序列;
class Solution { public: int maxProduct(vector<int>& nums) { //直接记忆化建二维数组建不了这么大,用容器建了这么大的也会超时 //记忆化存储一维数组; int m=nums.size(); if(m==0) return 0; int res=nums[0]; int dp=1,pre=1; int all_a=0,all_b=0;//分别为不为0的第一、二个负数到当前的乘积; int flag=0; for(int e:nums){ all_a*=e;all_b*=e; if(all_a==0) all_a=e; if(flag==1 && all_b==0) all_b=e; if(e==0) {flag=0;all_a=0;all_b=0;} if(e<0) flag++; dp=max(dp*e,e); if(all_a!=0) dp=max(dp,all_a); if(all_b!=0) dp=max(dp,all_b); res=max(res,dp); } return res; } };
动态规划更规范的写法:O(n)由于存在负数,因此i+1元素(记作e)位置的最小值与以i结尾的最大值和最小值都有关系,即应该在cur_max*e,cur_min*e,e中选择最大值和最小值更新,并记录当前最大值;
class Solution { public: int maxProduct(vector<int>& nums) { //建立一个dp数组,每次储存现在的最大最小值,并进行更新; int dp[2][2]; int len=nums.size(); if(len==0) return 0; dp[0][0]=nums[0],dp[0][1]=nums[0];//第二个下标0,1分别表示最大值和最小值; int res=nums[0]; for(int i=1;i<len;i++){ int x=i%2,y=(i+1)%2,n=nums[i]; dp[x][0]=max(max(dp[y][0]*n,dp[y][1]*n),n); dp[x][1]=min(min(dp[y][0]*n,dp[y][1]*n),n); //cout<<i<<"("<<x<<")"<<": "<<dp[x][0]<<","<<dp[x][1]<<endl; res=max(res,dp[x][0]); } return res; } };