113. Best Time to Buy and Sell Stock with Cooldown
View on NeetCode
View on LeetCode
Problem
You are given an array prices where prices[i] is the price of a given stock on the ith day.
Find the maximum profit you can achieve. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times) with the following restrictions:
- After you sell your stock, you cannot buy stock on the next day (i.e., cooldown one day).
Note: You may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again).
Example 1:
Input: prices = [1,2,3,0,2]
Output: 3
Explanation: transactions = [buy, sell, cooldown, buy, sell]
Example 2:
Input: prices = [1]
Output: 0
Constraints:
1 <= prices.length <= 50000 <= prices[i] <= 1000
Solution
Approach 1: State Machine DP
The key insight is to model three states: holding stock, sold (cooldown), and not holding (ready to buy).
Implementation
class Solution:
def maxProfit(self, prices: List[int]) -> int:
if not prices:
return 0
n = len(prices)
# Three states:
# hold: max profit when holding stock
# sold: max profit when just sold (must cooldown)
# rest: max profit when not holding and can buy
hold = -prices[0] # Buy on day 0
sold = 0
rest = 0
for i in range(1, n):
prev_hold = hold
prev_sold = sold
prev_rest = rest
# Can hold by keeping previous hold or buying from rest
hold = max(prev_hold, prev_rest - prices[i])
# Can be in sold state by selling from hold
sold = prev_hold + prices[i]
# Can be in rest by staying in rest or from cooldown after sold
rest = max(prev_rest, prev_sold)
# Maximum profit is either in sold or rest state
return max(sold, rest)
Approach 2: Simplified DP
class Solution:
def maxProfit(self, prices: List[int]) -> int:
if len(prices) <= 1:
return 0
n = len(prices)
# buy[i]: max profit on day i ending with a buy
# sell[i]: max profit on day i ending with a sell
buy = [0] * n
sell = [0] * n
buy[0] = -prices[0]
buy[1] = max(-prices[0], -prices[1])
sell[1] = max(0, buy[0] + prices[1])
for i in range(2, n):
# Buy today or keep previous buy state
buy[i] = max(buy[i-1], sell[i-2] - prices[i])
# Sell today or keep previous sell state
sell[i] = max(sell[i-1], buy[i-1] + prices[i])
return sell[n-1]
Approach 3: Space-Optimized
class Solution:
def maxProfit(self, prices: List[int]) -> int:
if not prices:
return 0
# sold: profit after selling (must cooldown next)
# hold: profit while holding stock
# rest: profit while resting (can buy)
sold = float('-inf')
hold = float('-inf')
rest = 0
for price in prices:
prev_sold = sold
prev_hold = hold
prev_rest = rest
hold = max(prev_hold, prev_rest - price)
sold = prev_hold + price
rest = max(prev_rest, prev_sold)
return max(sold, rest)
Complexity Analysis
- Time Complexity: O(n), where n is the number of days. Single pass through prices.
- Space Complexity: O(1) for space-optimized versions, O(n) for array-based versions.
Key Insights
-
State Machine: Three states: holding stock, just sold (cooldown required), and resting (can buy).
-
Cooldown Constraint: After selling, must wait one day before buying again. This is captured by buying from “rest” state, which comes from “sold - 1”.
- Transitions:
- Hold: Keep holding or buy from rest state
- Sold: Sell from hold state
- Rest: Stay in rest or cooldown from sold
-
No Simultaneous Transactions: Can only hold one stock at a time, enforced by state transitions.
-
Final Answer: Maximum of sold and rest states (not holding at end).
- Cooldown Implementation:
buy[i] = max(buy[i-1], sell[i-2] - prices[i])- buy from profit two days ago (after cooldown).