LeetCode 121/122/123/188/309 Best Time to Buy and Sell Stock Series
给出一个数组 代表股票价格
1 只允许交易一次
2 允许交易任意多次
3 最多交易两次
4 最多交易k次
5 允许交易任意多次 但是每次交易的时间有至少一天的cooldown期
1 我们只需要找到一前一后的ij指针 然后j指针减i指针差值最大即可。
从前往后遍历 维护一个截止到目前最小的price 维护另一个当前最大的profit/
核心代码:
for(int price: prices){
min = Math.min(min, price);
profit = Math.max(profit, price - min);
}
return profit;
2 这个实际上有点tricky,解法基于的原理是
我们把每一段上升的都加在一起 那么最终肯定大于等于 尾部-头部上升的。所以很简单 就是从头到尾遍历 只要后面大于前面 立刻把这个作为profit的一部分加到总profit里面。
核心代码:
for(int i = 1; i<prices.length; i++){
if(prices[i] > prices[i-1]){
profit += prices[i] - prices[i-1];
}
}
第二种方法给予的原理:always choose the closest peak after a vally, 虽然听起来像greedy但是可以通过反证法证明。
其实这个和方法一基于的原理差不多,但是写法复杂了一些
class Solution {
public int maxProfit(int[] prices) {
if(prices == null || prices.length == 0) return 0;
int i = 0;
int valley = prices[0];
int peak = prices[0];
int maxprofit = 0;
while(i < prices.length - 1) { //because we use prices[i+1] later, so i<prices.length-1
while(i < prices.length - 1 && prices[i] >= prices[i+1]) { //why we use = in here? becasue we want to go as far as we can
i++;
}
valley = prices[i]; //get a valley
while(i < prices.length - 1 && prices[i] <= prices[i+1]) {
i++;
}
peak = prices[i]; //get its closest peak
maxprofit += peak - valley; //accumulative maxprofit
}
return maxprofit;
}
}
3 这道题可以用DP去做 详见:https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/solution/
但是我们可以用one pass 去做
核心代码如下:
for (int price : prices) {
// the maximum profit if only one transaction is allowed
t1Cost = Math.min(t1Cost, price);
t1Profit = Math.max(t1Profit, price - t1Cost);
// reinvest the gained profit in the second transaction
t2Cost = Math.min(t2Cost, price - t1Profit);
t2Profit = Math.max(t2Profit, price - t2Cost);
}
4 最多K次 那这样的话 之前121-123的修改连就不能用了
这就不可避免的要DP了
dp[i][j] is defined as maximum profit from at most i transactions using prices[0…j]
so on day j, we have two options: do nothing, that makes dp[i][j] = dp[i][j-1]
or we choose to sell the stock: in order to sell the stock on day j, we have to bought it on day[0~j-1]
since we can’t sure which day is the day to buy in, so we have to iterate through every day to get the maximum
so we have to get max(dp[i-1][t-1] + prices[j] - prices[t]) where t from 0 to j-1
核心代码:
for (int i = 1; i <= k; i++) {
int max = - prices[0]; //initialize max for every row, so max is overall max for each row
for (int j = 1; j < len; j++) {
dp[i][j] = Math.max(dp[i][j-1], prices[j] + max);
max = Math.max(max, dp[i-1][j-1] - prices[j]); //the j in max is actually j-1
} //why this could work?
}
return dp[k][len - 1];
5 采用双一维DP数组的方式去解
int[] buy = new int[m];//buy[i] means: if we only give i days, then the Maximum profit which end with buying on day i or end with buying on a day before i and takes rest until the day i since then.
int[] sell = new int[m];//sell[i] means: if we only give i days, then the Maximum profit which end with selling on day i or end with selling on a day before i and takes rest until the day i since then.
核心代码:
for (int i = 2; i < prices.length; i++) {
buy[i] = Math.max(buy[i-1], sell[i-2] - prices[i]); //第i天买的最大利润是从 第i-1天买的最大利润 和 第i-2天卖的最大利润(因为 至少间隔一天) 之间取最大值
sell[i] = Math.max(sell[i-1], buy[i-1] + prices[i]); //第i天卖的最大利润是从 第i-1天卖的最大利润 和 第i-1天买的最大利润(因为买卖之间无需间隔一天) 之间取最大值
}
return sell[prices.length - 1];
总结一下就是前三道题目差不多的解法
后两道题 转k次需要用二维dp. cooldown一天 需要用两个dp数组。
就硬记吧。

浙公网安备 33010602011771号