309. Best Time to Buy and Sell Stock with Cooldown
At a Glance
- Topic: dp-2d
- Pattern: Dynamic Programming (finite state machine on timeline)
- Difficulty: Medium
- Companies: Google, Amazon, Adobe, Microsoft, Uber
- Frequency: High
- LeetCode: 309
Problem (one-liner)
Given daily prices, maximize profit with unlimited transactions but cannot buy on the day immediately after you sell (1-day cooldown). You may hold at most one share. Input: prices. Output: max profit.
Recognition Cues
- “Cooldown” after sell
- Stock problems as states: holding, not holding (free), cooldown
- Day DP transitions depend on previous state
Diagram
At-a-glance flow (replace with problem-specific Mermaid as you refine this note). camelCase node IDs; no spaces in IDs.
Loading diagram…
Approaches
- Brute force — recurse sell/buy/skip — exponential.
- Better — 2D
dp[day][state]table —O(n)time /O(n)space. - Optimal — three scalars rolling through days —
O(n)time /O(1)space. <- pick this in interview.
Optimal Solution
Go
package main
func maxProfitTable(prices []int) int {
length := len(prices)
if length == 0 {
return 0
}
holding := make([]int, length)
cooldown := make([]int, length)
free := make([]int, length)
holding[0] = -prices[0]
cooldown[0] = 0
free[0] = 0
for day := 1; day < length; day++ {
price := prices[day]
nextHolding := holding[day-1]
buyFromFree := free[day-1] - price
if buyFromFree > nextHolding {
nextHolding = buyFromFree
}
nextCooldown := holding[day-1] + price
nextFree := cooldown[day-1]
if free[day-1] > nextFree {
nextFree = free[day-1]
}
holding[day] = nextHolding
cooldown[day] = nextCooldown
free[day] = nextFree
}
last := length - 1
if cooldown[last] > free[last] {
return cooldown[last]
}
return free[last]
}
func maxProfit(prices []int) int {
length := len(prices)
if length == 0 {
return 0
}
holding := -prices[0]
cooldown := 0
free := 0
for day := 1; day < length; day++ {
price := prices[day]
nextHolding := holding
buyFromFree := free - price
if buyFromFree > nextHolding {
nextHolding = buyFromFree
}
nextCooldown := holding + price
nextFree := cooldown
if free > nextFree {
nextFree = free
}
holding = nextHolding
cooldown = nextCooldown
free = nextFree
}
if cooldown > free {
return cooldown
}
return free
}JavaScript
function maxProfit(prices) {
const length = prices.length;
if (length === 0) return 0;
let holding = -prices[0];
let cooldown = 0;
let free = 0;
for (let day = 1; day < length; day++) {
const price = prices[day];
const nextHolding = Math.max(holding, free - price);
const nextCooldown = holding + price;
const nextFree = Math.max(cooldown, free);
holding = nextHolding;
cooldown = nextCooldown;
free = nextFree;
}
return Math.max(cooldown, free);
}Walkthrough
prices = [1,2,3,0,2]
Track (holding, cooldown, free) rolling:
- Start:
(-1,0,0) - After each day update per transitions.
Invariant: holding is max cash if must hold stock; cooldown if must rest today after selling yesterday; free if can buy today.
Edge Cases
- Monotone decreasing → best
0 - Length
1→0
Pitfalls
- Allowing buy from
cooldownsame day (illegal by statement) - Wrong initialization of
holding
Similar Problems
- 121. Best Time to Buy and Sell Stock — one transaction.
- 122. Best Time to Buy and Sell Stock II — unlimited without cooldown.
- 416. Partition Equal Subset Sum — different domain, same “state over prefix” practice.
Variants
- Transaction fee per sale → subtract fee from sell transition.
- At most
ktransactions → add dimension.
Mind-Map Tags
#stock-dp #state-machine #cooldown #medium
Last updated on
Spotted something unclear or wrong on this page?