目录
题目描述
注意本题的只可以交易一次的这个条件
思路一
贪心算法:每一次记录到当前[0,i]之间的最小值,然后用当前prices[i]-min_price,迭代记录即可.
class Solution {
public:
int maxProfit(vector<int>& prices) {
int min_price = 1e+7;
int res = 0;
for (int i = 0; i < prices.size(); ++i) {
min_price = min(prices[i], min_price);
res = max(res, prices[i] - min_price);
}
return res;
}
};
思路二----动态规划
我当时做题时就是想不通---dp数组如何能够表明三种动作,保存,卖出,买入........(dp不应该用来保存动作,应该用来保存状态)
关键点:dp数组表示的是状态,状态只有两种:拥有和未拥有,就像女朋友一样(doge),我们使用dp[i][0]表示当前未拥有股票时的最大利润,dp[i][1]表示当前拥有股票的最大利润.
dp[i][0]可能是由两种情况变化而来,dp[i-1][0],之前就没拥有,dp[i-1][1]之前拥有,但是现在失去了.
dp[i][1]可能是由两种情况变化而来,dp[i-1][1],之前就有,dp[i-1][0],昨天没有,今天就有了.
就这样我们确定了dp的含义,递推公式,递归顺序是从前到后,第四步初始化dp[0][0]=0,dp[0][1]=-prices[0].第五步,手动推导dp数组.
就这样,代码就写好啦!
class Solution {
public:
int maxProfit(vector<int>& prices) {
vector<vector<int>> vec(prices.size(), vector<int>(2,0)); //(hang,vector<int>(lie,val))
vec[0][0] = 0; //不持有股票
vec[0][1] = -prices[0]; //持有股票
for (int i = 1; i < prices.size(); ++i) {
vec[i][0] = max(vec[i - 1][0], prices[i] + vec[i - 1][1]); //今天没有股票
vec[i][1] = max(vec[i - 1][0] - prices[i], vec[i - 1][1]); //今天拥有股票
}
return max(vec[prices.size() - 1][0], vec[prices.size() - 1][1]);
}
};
但是这代码有什么问题?它最大的问题在于没有限制说只能购买一次.它可以解决LeetCode122题
那么如何修改使其只能购买一次呢?
第i天买入股票,只能买入一次,那么就不能用之前的max(vec[i-1][0]-prices[i],vec[i-1][1])
vec[i-1][0]表示之前不知道多少次买卖后,失去股票时的最大利润,我们去掉这一项,只留下-prices[i],那么只表示当前买或者之前买,哪一次买的最便宜,就留下哪一次.
class Solution {
public:
int maxProfit(vector<int>& prices) {
if (prices.size() <= 1) return 0;
vector<vector<int>> vec(prices.size(), vector<int>(2,0)); //(hang,vector<int>(lie,val))
vec[0][0] = 0; //不持有股票
vec[0][1] = -prices[0]; //持有股票
for (int i = 1; i < prices.size(); ++i) {
vec[i][0] = max(vec[i - 1][0], prices[i] + vec[i - 1][1]); //今天卖掉股票
vec[i][1] = max(- prices[i], vec[i - 1][1]); //今天买入股票
}
return max(vec[prices.size() - 1][0], vec[prices.size() - 1][1]);
}
};
其实和上面的贪心算法思想是一样的.
小结
1.dp数组表示的是状态而不是动作
2.状态转移方程要明确转移的到底是什么状态,考不考虑之前状态的影响(vec[i-1][0]+prices[i]),还是只考虑当前状态(-prices[i]).