股票价格变动如下,什么时候买,什么时候卖,收益最大?
A brute-force solution
We can easily devise a brute-force solution to this problem: just try every possible
pair of buy and sell dates in which the buy date precedes the sell date.
#include<iostream>
using namespace std;
void brute_force(int a[],int len,int &buy,int &sell){
a[0]=0;
buy=0;//设定初值假定没有收益,则不购买
sell=0;//设定初值假定没有收益,则不购买
int sum=0;
//第i-1天买,第j天卖,最大收益存到a[0]
for(int i=1;i<len;i++){
for(int j=i;j<len;j++){
sum=0;
for(int k=i;k<=j;k++){
sum+=a[k];
}
if(sum>a[0]){
a[0]=sum;
buy=i-1;
sell=j;
}
}
}
}
int main()
{
int a[17]={0,13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
int buy,sell;
brute_force(a,17,buy,sell);
cout<<a[0]<<endl;
cout<<"buy: "<<buy<<endl;
cout<<"sell: "<<sell<<endl;
return 0;
}
A transformation —– divide-and-conquer
If we treat this row as an array A, shown in Figure 4.3, we now want to find the nonempty, contiguous subarray of A whose values have the largest sum. We call this contiguous subarray the maximum subarray. If all the array entries were nonnegative, then the maximum-subarray problem would present no challenge, since the entire array would give the greatest sum.
As Figure 4.4(a) shows, any contiguous subarray A[i…j] of A[low…high] must lie in exactly one of the following places:
- entirely in the subarray A[low…mid], so that low <= i <= j <= mid,
- entirely in the subarray A[mid+1…high], so that mid < i<= j <= high,
- crossing the midpoint, so that low <=i <= mid < j <=high.
In fact, a maximum subarray of A[low…high] must have the greatest sum over all subarrays entirely in A[low…mid], entirely in A[mid+1…high], or crossing the midpoint. We can find maximum subarrays of A[low…mid] and A[mid+1…high] recursively, because these two subproblems are smaller instances
of the problem of finding a maximum subarray.
#include<iostream>
using namespace std;
//存放购买股票的起始日期及获得的最大利润
struct result{
int buy;
int sell;
int profit;
};
result find_max_cross_subarray(int a[],int l,int mid,int r){
int l_max=-1000000;//假设这个值是无穷小
int l_sum=0;
int l_pos;
for(int i=mid;i>=0;i--){
l_sum+=a[i];
if(l_sum>l_max){
l_max=l_sum;
l_pos=i;
}
}
int r_max=-1000000;
int r_sum=0;
int r_pos;
for(int i=mid+1;i<=r;i++){
r_sum+=a[i];
if(r_sum>r_max){
r_max=r_sum;
r_pos=i;
}
}
result res;
res.buy=l_pos-1;
res.sell=r_pos;
res.profit=l_max+r_max;
return res;
}
//下面的递归分治,如果数组a仅有一个元素,可以直接判断收益是否小于等于0来决定购买与否
result find_max_subarray(int a[],int l,int r){
if(l==r){
result res;
res.buy=l-1;
res.sell=r;
res.profit=a[l];
return res;
}
else{
int mid=(l+r)/2;
result l_r=find_max_subarray(a,l,mid);
result r_r=find_max_subarray(a,mid+1,r);
result cross_r=find_max_cross_subarray(a,l,mid,r);
if(l_r.profit>=r_r.profit && l_r.profit>=cross_r.profit){
return l_r;
}
else if(r_r.profit>=l_r.profit && r_r.profit>=cross_r.profit){
return r_r;
}
else{
return cross_r;
}
}
}
int main()
{
int a[17]={0,13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
result res=find_max_subarray(a,1,16);
cout<<res.profit<<endl;
cout<<"buy: "<<res.buy<<endl;
cout<<"sell: "<<res.sell<<endl;
return 0;
}