2014年百度暑期实习招聘面试出现这个问题,其实是算法导论中讲解分治算法的一道题目。
问题:在某时刻买进某公司的股票,并在之后某个日期将其抛售,如何使得利益最大化,即卖出的价格和买进的价格之差最大。
分析:不妨用a[0] a[1] ...a[N]表示N+1天的股票价格,那么问题就是找到两点i和j使得a[j]-a[i]最大。
a[j]-a[i]=a[j]-a[j-1]+a[j-1]-a[j-2]+a[j-2]+...+a[i+1]-a[i]=(a[j]-a[j-1])+(a[j-1]-a[j-2])+....+(a[i+1]-a[i])
所以求解a[j]-a[i]问题转换为:先求出当天股票价格与前一天股票价格的差,用b[1]....b[N]表示,b[1]为a[1]-a[0]即第1天的股票价格与第0天股票价格只差。
求解数组b[1]...b[N]最大子数组和。
1.分治算法
最大子数组的和一定是三种情况中的某一种,b[low....high],low为中间位置。
(1) 完全位于子数组b[low..mid]中,因此low<=i<=j<=mid
(2)完全位于子数组b[mid+1..high]中,因此mid+1<=i<=j<=high
(3)跨越中点
这样可以把原问题分解成两个小的子问题。
1.分治算法求解代码
#include "stdafx.h"
#include<limits>
#include<iostream>
#include<vector>
using namespace std;
struct Node
{
int sum;
int left;
int right;
};
Node Find_Cross_Max(vector<int> a,int low,int mid,int high);
Node Find_Max(vector<int> a,int low,int high);
int _tmain(int argc, _TCHAR* argv[])
{
vector<int>a;
int x;
char s;
int tmp=0;
while((cin>>x)&&(cin.get(s)))
{
a.push_back(x-tmp);
tmp=x;
if(s=='\n')
break;
}
int N=a.size()-1;
Node n;
n=Find_Max(a,1,N);
cout<<n.left<<" "<<n.right<<" "<<n.sum<<endl;
return 0;
}
//分治算法求解最大子数组的和
Node Find_Cross_Max(vector<int>a,int low,int mid,int high)
{
int left_sum=numeric_limits<int>::min();
int left_max,right_max;
int sum=0;
for(int i=mid;i>=low;i--)
{
sum+=a[i];
if(sum>left_sum)
{
left_sum=sum;
left_max=i;
}
}
int right_sum=numeric_limits<int>::min();
sum=0;
for(int i=mid+1;i<=high;i++)
{
sum+=a[i];
if(sum>right_sum)
{
right_sum=sum;
right_max=i;
}
}
Node n;
n.left=left_max;
n.right=right_max;
n.sum=left_sum+right_sum;
return n;
}
Node Find_Max(vector<int>a,int low,int high)
{
Node mid_n,left_n,right_n;
if(low==high)
{
mid_n.left=low;
mid_n.right=high;
mid_n.sum=a[low];
return mid_n;
}
else
{
int mid=(low+high)/2;
left_n=Find_Max(a,low,mid);
right_n=Find_Max(a,mid+1,high);
mid_n=Find_Cross_Max(a,low,mid,high);
if(left_n.sum>right_n.sum && left_n.sum>mid_n.sum)
return left_n;
else if(mid_n.sum>left_n.sum && mid_n.sum>right_n.sum)
return mid_n;
else
return right_n;
}
}
方法2:
int max=a[0];
int sum=0;
int tm=0,left=0;
int right;
for(int i=0;i<7;i++)
{
sum+=a[i];
if(sum>max)
{
right=i;
left=tm;
max=sum;
}
if(sum<0)
{
tm=i+1;
sum=0;
}
}
cout<<left<<" "<<right<<" "<<max;