122. 买卖股票的最佳时机 II - 力扣(LeetCode)
股票系列:
LeetCode第 121 题:买股票的最佳时机(C++)_zj-优快云博客
LeetCode第 122 题:买股票的最佳时机II(C++)_zj-优快云博客
LeetCode第 123 题:买股票的最佳时机III(C++)_zj-优快云博客
LeetCode第 188 题:买股票的最佳时机IV(C++)_zj-优快云博客
LeetCode第 309 题:最佳买卖股票时机含冷冻期(C++)_zj-优快云博客
LeetCode第 714 题:买卖股票的最佳时机含手续费(C++)_zj-优快云博客
因为上一题dp,这一题一直想怎么dp,然后就卡壳了。。。
其实就一张图的事(来自官方题解:买卖股票的最佳时机 II - 买卖股票的最佳时机 II - 力扣(LeetCode)):
要想收益最大化,只要碰到波峰就卖,收益就是波峰减去波谷:
Total Profit = ∑ i ( height ( peak i ) − height ( valley i ) ) \text {Total Profit}=\sum_{i}\left(\text {height}\left(\text {peak}_{i}\right)-\text {height}\left(\text {valley}_{i}\right)\right) Total Profit=i∑(height(peaki)−height(valleyi))
其实这有点像贪心的思路
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
int vally = prices[0], peak = prices[0], res = 0;
int i = 0;
while(i < n-1){//
while(i < n-1 && prices[i] >= prices[i+1]) ++i;
vally = prices[i];
while(i < n-1 && prices[i] <= prices[i+1]) ++i;
peak = prices[i];//如果一直没有找到峰或者谷,那最后vally,peak均等于最后一个元素
res += peak - vally;
}
return res;
}
};
其实转化一下,当某个元素比它的前一个元素要大的时候,就可以累加差值,都不用考虑波峰波谷:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
int res = 0;
for(int i = 1; i < n; ++i){
if(prices[i] > prices[i-1]) res += prices[i] - prices[i-1];
}
return res;
}
};
至于这样为什么能行,可以看一下:暴力搜索、贪心算法、动态规划 - 买卖股票的最佳时机 II - 力扣(LeetCode)的方法二的解释。
动态规划
这个题动态规划还是可以用的,之前想不出状态怎么转移,看了下面的题解之后还是明白了。
注意题目给的数组是一只股票在不同日期的价格。
状态定义
每一天可能有三种动作:买,卖,什么都不做
二维dp:第一维表示日期(第几天),第二维表示(这一天结束之前)是否持有股票(1:有,0:无),数组值表示收益:
vector<vector<int>> dp(n, vector<int>(2, 0));
状态转移
第一种情况,当天(结束之前)手上没有股票,走到这一步有两种可能:
- 前一天手上就没有股票,今天什么都不做
- 前一天手上有股票,今天进行卖出(获得收益)
第二种情况,当天(结束之前)手上有股票,走到这一步也有两种可能:
- 前一天手上就有股票,今天什么都不做
- 前一天手上没有股票,今天进行了买入(花掉一笔钱)
我们要使得收益最大,所以状态转移的时候在两种情况中取收益较大者,有:
dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])
边界状态
第i天的状态只能由第i-1天的状态推导而来,那么i = 0(第一天)的状态定义为:
dp[0][0] = 0; //第一天没有股票,没有任何动作,收益为0
dp[0][1] = 0 - prices[0]; //第一天(结束之前)有股票,说明今天进行了买入,收益为负(花掉一笔钱)
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
if(n < 2) return 0;
//第一维表示日期,第二维表示是否持有股票(1:有,0:无),数组值表示收益
vector<vector<int>> dp(n, vector<int>(2, 0));
dp[0][0] = 0; //第一天没有股票,没买没卖,收益为0
dp[0][1] = 0 - prices[0]; //第一天有股票,说明买入了,收益为负(花掉一笔钱)
for(int i = 1; i < n; ++i){
dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i]);//第i天没有股票
dp[i][1] = max(dp[i-1][0] - prices[i], dp[i-1][1]);//第i天持有股票
}
//return max(dp[n-1][0], dp[n-1][1]);要想收益最大,最后一天肯定不会进行买入,所以dp[n-1][0]肯定更大
return dp[n-1][0];
}
};
这道题的dp其实不难写,但是很难解释,这位同学解释的很好:股票交易系列:贪心思想和动态规划 - 买卖股票的最佳时机 II - 力扣(LeetCode)