一、题目打卡
1.1 买股票的最佳时机
题目链接:. - 力扣(LeetCode)
// class Solution {
// public:
// int maxProfit(vector<int>& prices) {
// if(prices.size() <= 1) return 0;
// int res = 0;
// for(int i = 0 ; i < prices.size();i++){
// int max_ = *max_element(prices.begin() + i, prices.end());
// int min_ = *min_element(prices.begin(), prices.begin() + i);
// res = max(res, max_ - min_);
// }
// return res;
// }
// };
// class Solution {
// public:
// int maxProfit(vector<int>& prices) {
// int min_ = INT_MAX;
// int res = 0;
// for(int i = 0 ; i < prices.size();i++){
// min_ = min(min_, prices[i]);
// res = max(res, prices[i] - min_);
// }
// return res;
// }
// };
class Solution {
public:
int maxProfit(vector<int>& prices) {
vector<vector<int>> dp(1, vector<int>(2,0));
// vector<vector<int>> dp(prices.size(), vector<int>(2,0));
dp[0][0] = -prices[0]; // 持有这一笔股票
dp[0][1] = 0; // 未持有这一笔股票
for(int i = 1 ; i < prices.size();i++){
// dp[i][0] = max(dp[i - 1][1] - prices[i], dp[i - 1][0]);
// dp[i][0] = max(-prices[i], dp[i - 1][0]); // 因为这里只买一次,所以不存在累加,因而从未持有变成持有的时候,直接就是 -price[i]
// dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
// int tmp = dp[0][1];
dp[0][1] = max(dp[0][1], dp[0][0] + prices[i]);
dp[0][0] = max(dp[0][0], -prices[i]);
}
// return max(dp[prices.size() - 1][0], dp[prices.size()-1][1]);
return max(dp[0][0], dp[0][1]);
}
};
因为题目要求的是最终只有一次股票的买入和卖出,所以其实最直接的思想就是遍历整个prices,然后从当前节点之前取最小,当前节点之后取最大,然后在遍历的过程中,记录下来两者相减的最大值,也就是最终的结果,但是这样是 n^2 的时间复杂度,因而肯定最终通过不了,这里有一个小的tips我这个方法获得的是迭代器,需要进行取值的操作。
第二种思路是贪心的方法,其实也就是上面那个方法的优化版,考虑到最小值和最大值的计算,其实没有必要在遍历过程的每一次都进行,最小值其实只用统计一次,后来就不断计算当前值和这个最小值之间的区间就好了,这样其实也就是贪心的思路。
最后就是动态规划,相较于之前的动态规划,我认为这个重点在于理解动态规划状态的一个定义,对于动态规划而言,状态需要包括所有变化过程的一个动态的变量的描述,这个题目中,动态的遍历就被定义为:是否持有股票和从第一天到第 i 天所得到的最大的利润,而前者其实包含了四个层面的内容,持有股票有可能是当天买的,也有可能是继承的前一天的,未持有股票,有可能是当天卖掉了,也有可能是和前一天未持有一样的状态,这样也就描述清楚了整个动态变化的过程。
不过这个题目还有一个细节就是,如果只买一次的话,那么状态转移方程里面:持有股票这个状态如果是由前一天未持有股票转移而来,这样的情况下,不能加上前一天未持有的状态变量的值,因为只存在买一次的过程,加上了就是计算的累加,也就是多次购买。
1.2 买股票的最佳时机II
题目链接:. - 力扣(LeetCode)
// class Solution {
// public:
// int maxProfit(vector<int>& prices) {
// if(prices.size() == 1) return 0;
// // int result = 0;
// // int prediff = 0;
// // int curdiff = 0;
// // int tmp = 0; // 存储低谷 i 的位置
// // for(int i = 0, j = 1; j < prices.size();i++,j++){
// // curdiff = prices[j] - prices[i];
// // if(curdiff > 0 && prediff <=0){
// // tmp = i;
// // }
// // else if(curdiff <= 0 && prediff > 0){
// // result += prices[i] - prices[tmp];
// // }
// // else if(curdiff)
// // prediff = curdiff;
// // }
// // return result;
// int result = 0;
// for(int i = 0; i < prices.size() -1 ; i++){
// if(prices[i+1] - prices[i] >=0) result+=prices[i+1]-prices[i];
// }
// return result;
// }
// };
class Solution {
public:
int maxProfit(vector<int>& prices) {
vector<vector<int>> s(1, vector<int>(2,0));
s[0][0] = 0;
s[0][1] = -prices[0]; // 持有股票
for(int i = 0 ; i < prices.size() ; i++){
int tmp = s[0][0];
s[0][0] = max(s[0][1] + prices[i], s[0][0]);
s[0][1] = max(s[0][1], s[0][0] - prices[i]);
}
return max(s[0][1], s[0][0]);
}
};
这个就是重复多次购买的情况,在1.1 也分析清楚了。