Problem 309: Best Time to Buy and Sell Stock with Cooldown
Given an integer array prices where prices[i] represents the stock price on day i. Design an algorithm to calculate the maximum profit under the constraint that you cannot buy stock on the day after selling (one-day cooldown period).
Dynamic Programming Approach
The key to solving this problem lies in properly defining states. Building upon the two-state model from the unlimited transactions problem, we introduce an additional cooldown state.
State Definition
Define dp[i][j] as the maximum cash on day i under state j:
| State Index | Meaning |
|---|---|
| 0 | Holding stock (acquired on current or previous days) |
| 1 | Not holding, and not in cooldown (previously sold, already past cooldown) |
| 2 | Not holding, sold today |
| 3 | Cooldown state (the day after selling) |
State Transitions
State 0 (Holding):
- Continue holding:
dp[i-1][0] - Buy today from cooldown:
dp[i-1][3] - prices[i] - Buy today from regular selling state:
dp[i-1][1] - prices[i]
State 1 (Regular No-Hold):
- Stay in this state:
dp[i-1][1] - Transition from cooldown:
dp[i-1][3]
State 2 (Sold Today):
- Must have been holding yesterday:
dp[i-1][0] + prices[i]
State 3 (Cooldown):
- Must have sold yesterday:
dp[i-1][2]
Implementation
class Solution {
public:
int maxProfit(vector<int>& prices) {
int days = prices.size();
if (days == 0) return 0;
vector<array<int, 4>> dp(days);
dp[0][0] = -prices[0]; // Buy on day 0
dp[0][1] = dp[0][2] = dp[0][3] = 0;
for (int i = 1; i < days; i++) {
dp[i][0] = max({dp[i-1][0], dp[i-1][3] - prices[i], dp[i-1][1] - prices[i]});
dp[i][1] = max(dp[i-1][1], dp[i-1][3]);
dp[i][2] = dp[i-1][0] + prices[i];
dp[i][3] = dp[i-1][2];
}
return max({dp[days-1][1], dp[days-1][2], dp[days-1][3]});
}
};
- Time Complexity: O(n)
- Space Complexity: O(n)
Problem 714: Best Time to Buy and Sell Stock with Transaction Fee
Given an array prices where prices[i] is the stock price on day i, and an integer fee representing the transaction cost. You may complete unlimited transactions, but each transaction incurs a one-time fee. You must sell before buying again.
Dynamic Programming Approach
This problem extends the unlimited transactions model by incorporating a transaction cost. The state space remains minimal with just two states.
State Definition
| State | Meaning |
|---|---|
| 0 | Holding one share |
| 1 | Not holding any shares |
State Transitions
Holding State:
- Keep holding:
dp[i-1][0] - Buy today:
dp[i-1][1] - prices[i]
Not-Holding State:
- Keep not holding:
dp[i-1][1] - Sell today:
dp[i-1][0] + prices[i] - fee
Implementation
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int days = prices.size();
vector<array<int, 2>> dp(days);
dp[0][0] = -prices[0]; // Initial purchase
dp[0][1] = 0;
for (int i = 1; i < days; i++) {
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] - fee);
}
return max(dp[days-1][0], dp[days-1][1]);
}
};
- Time Complexity: O(n)
- Space Complexity: O(n)
Space Optimization
Since each state only depends on the previous day, we can reduce space to O(1):
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int hold = -prices[0];
int cash = 0;
for (int i = 1; i < prices.size(); i++) {
int prevHold = hold;
hold = max(hold, cash - prices[i]);
cash = max(cash, prevHold + prices[i] - fee);
}
return cash;
}
};