在股市的交易日中,假设最多可进行两次买卖(即买和卖的次数均小于等于2),规则是必须一笔成交后进行另一笔(即买-卖-买-卖的顺序进行)。给出一天中的股票变化序列,请写一个程序计算一天可以获得的最大收益。请采用实践复杂度低的方法实现。
给定价格序列prices及它的长度n,请返回最大收益。保证长度小于等于500。
测试样例:
[10,22,5,75,65,80],6
返回:
87
作为一个编程入门者,没有修炼过各种算法,做过的题也不多,刚遇到这种题目时是很头疼的,脑子里自动飘过了无数个循环的嵌套的暴力做法。后来仔细想了一下,最多可以进行两次买卖,则应该将这两次买卖分开来计算。第二次的买和卖一定比第一次的买和卖晚,则定义一个分割price的变量i,从2循环到n-1。表示第一次和第二次以第i天为界限,则先写出最外层循环:
for(i=2;i<n-1;i++)
{
}
买和卖不能在同一天,i是一个边界值,我定义左半边不能遍历到第i天,右半边从第i天开始遍历。之后开始进行左半部分和右半部分的循环,分别求出左半部分和右半部分里的最大差值max_front和max_back,然后储存max_front+max_back的最大值。最开始求最大差值时我用的是暴力的两层循环,逐个元素与其后所有元素进行运算,:
for(m=0;m<i;m++)
{
for(n=m+1;n<i;n++)
{
if(max_front<(a[n]-a[m]))
max_front=a[n]-a[m];
}
}
这种方法的时间复杂度为o(n^2)。后来想到,如果我定义一个数组max_front[i],用来存放每个数与其他数之间的最大差值从后往前遍历,记录下来最大值,当前最大值减去a[i]就是他的最大差值。这种方法的时间复杂度为o(n),但定义了两个数组,牺牲了一些空间来换取时间。
for(m=i-1;m>=0;m--)
{
if(max_value<a[m])
max_value=a[m];
max_front[m]=max_value-a[m];
}
此处需要注意的是,右半部分的数组的循环变量不能和外层循环一样,需另外定义一个。
再用两个for循环得到max_front和max_back数组中的最大值,再储存两个数的和的最大值,即为最后的解。
末尾附上程序源代码,变量定义有点繁琐,编程小白,请谅解
#include<stdio.h>
#include<string.h>
int main()
{
int N,i,j,m,n;
scanf("%d",&N);
int a[N];
for(i=0;i<N;i++)
scanf("%d",&a[i]);
int max=0;
for(i=2;i<N-1;i++)
{
int max_front[i];
int max_value=0;
for(m=i-1;m>=0;m--)
{
if(max_value<a[m])
max_value=a[m];
max_front[m]=max_value-a[m];
}
int max_Front=0;
for(m=0;m<i;m++)
{
if(max_front[m]>max_Front)
max_Front=max_front[m];
}
int max_back[N-i];
max_value=0;
for(m=N-1,j=0;m>=i;m--,j++)
{
if(max_value<a[m])
max_value=a[m];
max_back[j]=max_value-a[m];
}
int max_Back=0;
for(m=0;m<N-i;m++)
{
if(max_back[m]>max_Back)
max_Back=max_back[m];
}
if(max<(max_Back+max_Front))
max=max_Back+max_Front;
}
printf("%d",max);
return 0;
}