121. 买卖股票的最佳时机
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。
注意:你不能在买入股票前卖出股票。
示例 1:
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
示例 2:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
题解:动态规划
思维:
在只有i天时,第i天要么参与买卖股票,要么不参与买卖股票。
若是第i天参与,则他一定就是股票最大价格;
若是第i天不参与,则买卖股票为前面i-1天的事情。
所以不妨设dp[i]为前i天的最大收益,所以可列出状态转移方程:
dp[i]=max(dp[i-1],prices[i]-min)
即如果第i天不参与则前i天的最大收益与前i-1天的最大收益是一样的。
而若第i天参与了,则他一定为卖价,而最小价格在前面可以找到。
----------注意!dp[i]的之所以那样设其实也和题意有关系,因为题意其实就是求在有i天时我们的最大收益是多少。
所以记得动态规划题一定要捕捉好题意,因为动态规划就是将大问题分解为几个子问题,所以能分解的前提是你要先捕捉到大问题的含义。---------
所以代码如下:
#define max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))//采用宏定义的方式定义max与Min
int maxProfit(int* prices, int pricesSize){
if(pricesSize==0||pricesSize==1)//先剔除这些情况
return 0;
int dp[pricesSize];
dp[0]=0;//动态规划自然要设立边界
int min = prices[0];
for(int i=1;i<pricesSize;i++)
{
dp[i]=max(dp[i-1],prices[i]-min);
min=Min(prices[i],min);
}
return dp[pricesSize-1];
}
当然可以用滚动数组进行空间换时间的优化:
代码:
#define max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
int maxProfit(int* prices, int pricesSize){
if(pricesSize==0||pricesSize==1)
return 0;
int first,second;//以first,second定义初末状态
second=0;//先给second赋值其实就是给下一个状态的first赋值
int min = prices[0];
for(int i=1;i<pricesSize;i++)
{
first=second;
second=max(first,prices[i]-min);
min=Min(prices[i],min);
}
return second;
}