题目描述
给定一个数组,它的第 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。
思路
定义求解问题:
对于每一天,可能的操作有两种:买入、卖出。
我们将dp[i][0]定义为在第i天买入股票的利润,dp[i][1]定义为卖出股票时候的利润。由于本题目只能买卖一次,因此买入的时候利润应该就是负数。
状态转移方程:
首先状态转移一共有4种:
- 0->0:表示前一天空仓,今天也继续空仓
- 0->1:表示前一天空仓,今天买入股票
- 1->0:表示前一天持有股票,今天卖掉
- 1->1:表示前一天持有股票,今天继续持有
因此:
- dp[i][0] = max(dp[i-1][0], dp[i-1][1] + price[i])
- dp[i][1] = max(dp[i-1][1], -price[i]) (由于是只能够买一次,因此买的时候利润只和当前价格有关系,和之前的状态没关系)
边界条件:
- dp[0][0] = 0;
- dp[0][1] = -pirce[0]
实现
/*
我们定义:
d[i][0]为在第i天没有买入股票的情况下的利润
d[i][1]为在第i天持有股票的情况下的利润
0->0状态表示,一直没有买入
0->1状态表示,买入股票
1->0状态表示,之前有股票现在卖出
1->1状态表示,继续持有股票
0->0 1->0
因此,dp[i][0] = max(dp[i-1][0]:继续空仓,dp[i-1][1] + price[i]:卖出股票)
1->1 0->1
dp[i][1] = max(dp[i-1][1]:继续持有,-price[i]:买入股票)
*/
#define max(a,b) (a>b?a:b)
int maxProfit(int* prices, int pricesSize){
if(pricesSize==0||pricesSize==1)
return 0;
int **dp = (int**)malloc(sizeof(int*)*pricesSize);
for(int i = 0; i< pricesSize; i++)
dp[i] = (int*)malloc(sizeof(int)*2);
for (int i = 0; i < pricesSize; i++) {
// 边界条件,单独定义买与不买的状态
if(i - 1 == -1){
dp[i][0] = 0;
dp[i][1] = -prices[i];
}else{
dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i]);
dp[i][1] = max(dp[i-1][1], -prices[i]);
}
}
return dp[pricesSize - 1][0];
}