首页 > 代码库 > 动态规划:最大连续子序列乘积

动态规划:最大连续子序列乘积

题目描述:

给定一个浮点数序列(可能有正数、0和负数),求出一个最大的连续子序列乘积。

分析:若暴力求解,需要O(n^3)时间,太低效,故使用动态规划。
data[i]:第i个数据,dp[i]:以第i个数结尾的连续子序列最大乘积,
若题目要求的是最大连续子序列和,则易确定状态转移方程为:
dp[i]=max(data[i],dp[i-1]+data[i])(dp[i]为以第i个数结尾的连续子序列最大和)

但乘积存在负负得正的问题,即原本很小的负数成了一个负数反而变大了,(负数逆袭了),

故不能照抄加法的转移方程,为了解决这个问题,需要定义两个数组:

dp1[i]:以第i个数结尾的连续子序列最大乘积
dp2[i]:以第i个数结尾的连续子序列最小乘积
转移方程:
dp1[i]=max(data[i],dp1[i-1]*data[i],dp2[i-1]*data[i]);

dp2[i]=min(data[i],dp1[i-1]*data[i],dp2[i-1]*data[i]);

最后遍历dp1得到最大值即为答案。

代码如下:

#include<stdio.h>
double max(double a,double b){return a>b?a:b;}
double min(double a,double b){return a<b?a:b;}
double dp1[100001];
double dp2[100001];
double data[100001];
double helper(double data[],int n)
{
  dp1[0]=data[0];
  dp2[0]=data[0];
  for(int i=1;i<n;i++)
  {
	  dp1[i]=max(data[i],max(dp1[i-1]*data[i],dp2[i-1]*data[i]));
	  dp2[i]=min(data[i],min(dp1[i-1]*data[i],dp2[i-1]*data[i]));
  }
  double ans=dp1[0];
  for(int i=1;i<n;i++)
  {
	  ans=max(ans,dp1[i]);
  }
  return ans;
}

 
int main(void)
{
    int i,n;
    while(scanf("%d",&n)!=EOF)
    {
        for(i=0; i<n; ++i)
        {
            scanf("%lf", &data[i]);
        }
        double ans = helper(data, n);
        printf("%lf\n",ans);
    }
    return 0;
}
其实还可以对空间复杂度进行化简,代码如下:

double helper(double data[], int n)
{
    double ans = data[0];
    double localMax = data[0];
    double localMin = data[0];
    for(int i=1; i<n; ++i)
    {
        double t1 = max(data[i], max(localMax*data[i], localMin*data[i]) );
        double t2 = min(data[i], min(localMax*data[i], localMin*data[i]) );
 
        localMax = t1;
        localMin = t2;
 
        ans = localMax > ans ? localMax : ans;
    }
 
    return ans;
}



动态规划:最大连续子序列乘积