美团2016年招聘笔试题:股票交易日

题目描述 
        在股市的交易日中,假设最多可进行两次买卖(即买和卖的次数均小于等于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;
}


猜你喜欢

转载自blog.csdn.net/q_m_x_d_d_/article/details/80057997