You are given an integer array prices where prices[i] is the price of NeetCoin on the ith day.
You may buy and sell one NeetCoin multiple times with the following restrictions:
You may complete as many transactions as you like.
Return the maximum profit you can achieve.
Example 1:
Input: prices = [1,3,4,0,4]
Output: 6Explanation: Buy on day 0 (price = 1) and sell on day 1 (price = 3), profit = 3-1 = 2. Then buy on day 3 (price = 0) and sell on day 4 (price = 4), profit = 4-0 = 4. Total profit is 2 + 4 = 6.
Example 2:
Input: prices = [1]
Output: 0Constraints:
1 <= prices.length <= 50000 <= prices[i] <= 1000
You should aim for a solution as good or better than O(n) time and O(n) space, where n is the size of the input array.
Try to think in terms of recursion and visualize it as a decision tree. Can you determine the possible decisions at each recursion step? Also, can you identify the base cases and the essential information that needs to be tracked during recursion?
At each recursion step, we can buy only if we haven't already bought a coin, or we can sell if we own one. When buying, we subtract the coin value, and when selling, we add it. We explore all possible buying and selling options recursively, iterating through the coins from left to right using index i. For the cooldown condition, if we buy a coin, we increment the index i by two.
We can use a boolean variable canBuy to indicate whether buying is allowed at the current recursive step. If we go out of bounds, we return 0. This approach is exponential. Can you think of a way to optimize it?
We can use memoization to cache the results of recursive calls and avoid recalculations. A hash map or a 2D array can be used to store these results.
Before attempting this problem, you should be comfortable with:
This problem is about deciding the best days to buy and sell a stock to maximize profit, with one important rule: after selling a stock, you must wait one day before buying again (cooldown).
At every day, we have two possible states:
Using recursion, we try all possible decisions starting from day 0 and choose the one that gives the maximum profit.
At each step, we either:
The recursive function represents:
"What is the maximum profit we can make starting from day i, given whether we are allowed to buy or not?"
dfs(i, buying):i represents the current daybuying indicates whether we are allowed to buy (true) or must sell (false)i goes beyond the last day:0 because no more profit can be made0 with buying = trueclass Solution:
def maxProfit(self, prices: List[int]) -> int:
def dfs(i, buying):
if i >= len(prices):
return 0
cooldown = dfs(i + 1, buying)
if buying:
buy = dfs(i + 1, not buying) - prices[i]
return max(buy, cooldown)
else:
sell = dfs(i + 2, not buying) + prices[i]
return max(sell, cooldown)
return dfs(0, True)This problem asks for the maximum profit from buying and selling stocks, with the restriction that after selling a stock, you must wait one day before buying again (cooldown).
The recursive solution tries all possible choices, but it repeats the same calculations many times. To make it efficient, we use Dynamic Programming (Top-Down) with memoization.
We define a state using:
ibuying = true) or must sell (buying = false)For each state, we store the best profit we can achieve so that we never compute it again.
dp where:(i, buying)i with the given statedfs(i, buying):i is the current daybuying indicates whether we can buy or must selli is beyond the last day:0 since no more profit can be made(i, buying) is already in dp:dpdp0 with buying = trueclass Solution:
def maxProfit(self, prices: List[int]) -> int:
dp = {} # key=(i, buying) val=max_profit
def dfs(i, buying):
if i >= len(prices):
return 0
if (i, buying) in dp:
return dp[(i, buying)]
cooldown = dfs(i + 1, buying)
if buying:
buy = dfs(i + 1, not buying) - prices[i]
dp[(i, buying)] = max(buy, cooldown)
else:
sell = dfs(i + 2, not buying) + prices[i]
dp[(i, buying)] = max(sell, cooldown)
return dp[(i, buying)]
return dfs(0, True)This problem is about maximizing stock trading profit with a cooldown rule:
after selling a stock, you must wait one full day before buying again.
Instead of using recursion, we solve this using bottom-up dynamic programming, where we build the solution starting from the last day and move backward to day 0.
At every day, we only care about two possible states:
For each day and state, we compute the maximum profit possible from that point onward and store it in a table.
This way, future decisions are already known when we process earlier days.
n be the number of days.dp of size (n + 1) x 2:dp[i][1] → maximum profit starting at day i when we are allowed to buydp[i][0] → maximum profit starting at day i when we are holding a stock0 since no profit can be made after the last day.n - 1 down to 0.i, evaluate both states:dp[i][1]dp[i][0]dp[0][1], meaning:0 with permission to buydp[0][1]class Solution:
def maxProfit(self, prices: List[int]) -> int:
n = len(prices)
dp = [[0] * 2 for _ in range(n + 1)]
for i in range(n - 1, -1, -1):
for buying in [True, False]:
if buying:
buy = dp[i + 1][False] - prices[i] if i + 1 < n else -prices[i]
cooldown = dp[i + 1][True] if i + 1 < n else 0
dp[i][1] = max(buy, cooldown)
else:
sell = dp[i + 2][True] + prices[i] if i + 2 < n else prices[i]
cooldown = dp[i + 1][False] if i + 1 < n else 0
dp[i][0] = max(sell, cooldown)
return dp[0][1]This problem follows the same idea as the previous dynamic programming solutions:
we want to maximize profit while respecting the cooldown rule (after selling, we must wait one day before buying again).
In the bottom-up DP approach, we only ever use values from the next day and the day after next. That means we do not need a full DP table — we can compress the state into a few variables.
Instead of storing results for every day, we keep track of:
By updating these values while iterating backward, we achieve the same result using constant space.
dp1_buy: profit if we can buy on the next daydp1_sell: profit if we can sell on the next daydp2_buy: profit if we can buy two days ahead (used after selling)dp2_buydp1_buy and dp1_selldp1_buy represents the maximum profit starting from day 0 with permission to buydp1_buyclass Solution:
def maxProfit(self, prices: List[int]) -> int:
n = len(prices)
dp1_buy, dp1_sell = 0, 0
dp2_buy = 0
for i in range(n - 1, -1, -1):
dp_buy = max(dp1_sell - prices[i], dp1_buy)
dp_sell = max(dp2_buy + prices[i], dp1_sell)
dp2_buy = dp1_buy
dp1_buy, dp1_sell = dp_buy, dp_sell
return dp1_buyAfter selling, you must skip one day before buying again. A common mistake is transitioning directly to the buying state on the next day instead of skipping to i + 2.
# Wrong: no cooldown after selling
sell = dfs(i + 1, True) + prices[i] # Should be i + 2Mixing up which state allows buying versus selling leads to subtracting when you should add (or vice versa). When buying=True, you subtract the price; when buying=False, you add it.
When iterating backward and accessing dp[i + 2], forgetting to check bounds causes index out of range errors. The DP table needs size n + 2 or proper boundary checks.