問題描述:某公司股票,給出n天內的股票價格,判斷什麼時候買入股票,什麼時候賣出股票收益最大
天 | 0 | 1 | 2 | 3 | 4 |
價格 | 10 | 11 | 7 | 10 | 6 |
變化 | 1 | -4 | 3 | -4 |
問題轉換: 將變化看成一個數組即A[4]=[1,-4,3,-4], 求解A的最大子數組(即子數組各項和最大)
解法:
設數組爲A[n].(n個元素)
一、暴力求解(遍歷)
思路:遍歷所有子數組(時間爲)
代碼:
#include<iostream>
using namespace std;
int* FindMaxSubarray(int* A, int n)
{
int * B=new int[3];
B[0]=A[0]; //最大子數組和
B[1]=0; //最大子數組最左邊元素下標
B[2]=n-1; //最大子數組最右邊元素下標
for(int i=0;i<n;i++)
{
int sum=0;
for(int j=i;j<n;j++)
{
sum+=A[j];
if(sum>B[0])
{
B[0]=sum;
B[1]=i;
B[2]=j;
}
}
}
return B;
}
int main()
{
int A[16]={13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
int *B={0};
B=FindMaxSubarray(A,16);
cout<<"the maximum subarray is from A["<<B[1]<<"] to A["<<B[2]<<"]"<<endl;//結果爲A[7]到A[10]
cout<<"the maximum sum is "<<B[0]<<endl;//結果爲43
return 0;
}
二、分治策略(時間爲)
思路:B[low..high]的一個最大子數組所處位置必然是以下三種情況之一:
1完全位於A[low...mid]中
2.完全位於A[mid+1,high]中
3.跨越中點的子數組和中的最大者(找出形如A[i,mid]和A[mid+1,j]中的最大子數組,再合併)(時間爲)
代碼:
#include<iostream>
using namespace std;
int* FindCross(int* A, int n,int m, int mid)
{
int * B=new int[3];
int left_max=A[mid];
int sum1=left_max;
int left_index=mid;
for(int i=mid-1;i>=n;i--)
{
sum1+=A[i];
if(sum1>left_max)
{
left_max=sum1;
left_index=i;
}
}
int right_max=A[mid+1];
int sum2=right_max;
int right_index=mid+1;
for(int j=mid+2;j<=m;j++)
{
sum2+=A[j];
if(sum2>right_max)
{
right_max=sum2;
right_index=j;
}
}
B[0]=left_max+right_max;
B[1]=left_index;
B[2]=right_index;
return B;
}
int* FindMaxSubarray(int* C, int k, int t)
{
if (k==t)
{
int * D_0=new int[3];
D_0[0]=C[k];
D_0[1]=D_0[2]=k;
return D_0;
}
else
{
int * D_1=new int[3];//左半邊子數組的最大子數組
int * D_2=new int[3]; // 右半邊子數組的最大子數組
int * D_3=new int[3]; // 跨越中間元素所有子數組中的最大子數組
int mid1=(k+t)/2;
D_1=FindMaxSubarray(C, k, mid1);
D_2=FindMaxSubarray(C, mid1+1, t);
D_3=FindCross(C,k,t,mid1);
if (D_1[0]>D_2[0] && D_1[0]>D_3[0])
return D_1;
else if (D_2[0]>D_1[0] && D_2[0]>D_3[0])
return D_2;
else
return D_3;
}
}
int main()
{
int arr[16]={13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
int *E={0};
E=FindMaxSubarray(arr,0,15);
cout<<"the maximum subarray is from arr["<<E[1]<<"] to arr["<<E[2]<<"]"<<endl;//結果爲arr[7]到arr[10]
cout<<"the maximum sum is "<<E[0]<<endl;//結果爲43
return 0;
}
三、非遞歸,線性時間的算法(時間爲)
思路:任何負的項不可能作爲最大子數組的起點;任何和爲負的子數組不可能是最大子數組的前綴;
代碼:
#include<iostream>
using namespace std;
int* FindMaxSubarray(int* A, int k, int t)
{
int *B= new int[3];
B[0]=A[k];
B[1]=k;
B[2]=k;
int sum=0;
for(int i=k;i<=t;i++)
{
if (sum>0)
sum+=A[i];
else
{
B[1]=i;
sum=A[i];
}
if (sum>B[0])
{
B[0]=sum;
B[2]=i;
}
}
return B;
}
int main()
{
int arr[16]={13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
int *E={0};
E=FindMaxSubarray(arr,0,15);
cout<<"the maximum subarray is from arr["<<E[1]<<"] to arr["<<E[2]<<"]"<<endl;//結果爲arr[7]到arr[10]
cout<<"the maximum sum is "<<E[0]<<endl;//結果爲43
return 0;
}