解法一:动态规划第一版
主要思想是填profit数组,profit [ i ]表示在第i天的最大的利润为多少,如果第i天没有卖出情况,则与profit[ i -1 ]相同,否则要找出自所有可能的上一个卖出日以来,最大的利润,当上一个卖出日为j时,日i的利润表示为profit [ i ] + prices[ i - 1 ] + dp[ j ][ i ](注意prices下标从0开始,所以要减一,其中dp[ j ][ i ]表示从日j到日i的最小价格,是在之前的循环中算出来的)
但由于dp记录的最小价格数组占用了O(n^2)的额外空间,所以会MLE,优化见下一个解法
class Solution {
public:
int maxProfit(vector<int> &prices) {
int n=prices.size();
if(n<2)
{
return 0;
}
vector<vector<int> > dp(n+1,vector<int>(n+1,0));
//i stands for selling time
for(int i=1;i<=n;++i)
{
//j stands for buying time
for(int j=1;j<=i;++j)
{
//dp[j][i] stands for start from day j,until selling day(day i),the lowest price
//careful prices index need to minus one
if((i-1)>=j)
{
dp[j][i]=dp[j][i-1]>prices[i-1]?prices[i-1]:dp[j][i-1];
}
else
{
dp[j][i]=prices[i-1];
}
}
}
vector<int > profit(n+1,0);
for(int i=2;i<=n;++i)
{
profit[i]=profit[i-1];
for(int j=i-1;j>=1;--j)
{
int tmp=profit[j]+(prices[i-1]-dp[j][i]);
if(tmp>profit[i])
{
profit[i]=tmp;
}
}
}
return profit[n];
}
};
解法二:动态规划第二版
class Solution {
public:
int maxProfit(vector<int> &prices) {
int n=prices.size();
if(n<2)
{
return 0;
}
vector<int > profit(n+1,0);
for(int i=2;i<=n;++i)
{
profit[i]=profit[i-1];
int min=prices[i-1];//record the min prices between j and i,
for(int j=i-1;j>=1;--j)
{
min=prices[j-1]>min?min:prices[j-1];
int tmp=profit[j]+(prices[i-1]-min);
if(tmp>profit[i])
{
profit[i]=tmp;
}
}
}
return profit[n];
}
};
不会再有MLE,但是填profit数组的时间复杂度为O(n^2),在大数据时TLE了,需要更进一步的优化,见下一个解法
解法三:贪婪解法
class Solution {
public:
int maxProfit(vector<int> &prices) {
int n=prices.size();
if(n<2)
{
return 0;
}
int res=0;
int curVal=prices[0];
for(int i=1;i<prices.size();++i)
{
if(prices[i]>curVal)
{
res+=(prices[i]-curVal);
curVal=prices[i];
}
else
{
curVal=prices[i];
}
}
return res;
}
};
一般情况下如果没有贪婪解法的话,那么上一个动态规划的解法理应是最优的解法了,但此题确实存在贪婪解法,需要同胞们在做题之前好好分析清楚题目才能发现贪婪解法。
注意观察到2个现象:1.如果当前价格比前一日的价格低,那么前一日的价格是无效的,因为当后续日子中出现高价我们需要卖出股票时,以当前日的价格买入优于前一日的价格买入;2.如果当前日的价格比前一日的价格高,那么当前日可以卖出股票,买入日为前一日,因为如果当前日不卖出,攒着等待后续日子中出现更高的价格时卖出,得到的收益和当前日卖出,然后在当前日再买入,等到后续同样的日子卖出时收益是一样的。