Best Time to Buy and Sell Stock II
Difficulty: Medium Source: NeetCode
Problem
You are given an integer array
priceswhereprices[i]is the price of a given stock on thei-th day.On each day, you may decide to buy and/or sell the stock. You can only hold at most one share of the stock at any time. However, you can buy it then immediately sell it on the same day.
Return the maximum profit you can achieve.
Example 1: Input:
prices = [7, 1, 5, 3, 6, 4]Output:7Explanation: Buy on day 2 (price=1), sell on day 3 (price=5), profit=4. Buy on day 4 (price=3), sell on day 5 (price=6), profit=3. Total=7.Example 2: Input:
prices = [1, 2, 3, 4, 5]Output:4Explanation: Buy on day 1, sell on day 5. Profit=4.Example 3: Input:
prices = [7, 6, 4, 3, 1]Output:0Explanation: No profitable transaction possible.Constraints:
1 <= prices.length <= 3 * 10^40 <= prices[i] <= 10^4
Prerequisites
Before attempting this problem, you should be comfortable with:
- Greedy algorithms — making locally optimal choices that lead to a global optimum
- Peaks and valleys — identifying upward and downward trends in a sequence
1. Peaks and Valleys
Intuition
To maximise profit, we want to buy at every valley (local minimum) and sell at every peak (local maximum). Between any valley and peak, we capture the full upward movement of the stock price.
Scan through the prices and whenever the current price is lower than the next price, buy (or keep holding). When the current price is higher than the next, sell. Accumulate all upward movements.
Algorithm
- Initialize
profit = 0,i = 0. - While
i < n - 1:- Find valley: while
prices[i] >= prices[i + 1], incrementi. - Find peak: while
prices[i] <= prices[i + 1], incrementi. - Add
prices[peak] - prices[valley]toprofit.
- Find valley: while
- Return
profit.
Solution
def maxProfit(prices):
profit = 0
i = 0
n = len(prices)
while i < n - 1:
# Find valley
while i < n - 1 and prices[i] >= prices[i + 1]:
i += 1
valley = prices[i]
# Find peak
while i < n - 1 and prices[i] <= prices[i + 1]:
i += 1
peak = prices[i]
profit += peak - valley
return profit
print(maxProfit([7, 1, 5, 3, 6, 4])) # 7
print(maxProfit([1, 2, 3, 4, 5])) # 4
print(maxProfit([7, 6, 4, 3, 1])) # 0
Complexity
- Time:
O(n) - Space:
O(1)
2. Greedy (Sum Positive Differences)
Intuition
Here is the key insight that simplifies everything: since we can buy and sell on consecutive days, we can decompose any profit into the sum of single-day gains.
For example, buying at price 1 on day 1 and selling at price 5 on day 4 gives profit 4. But this is the same as buying and selling each day: (2-1) + (3-2) + (4-3) + (5-4) = 1 + 1 + 1 + 1 = 4. The intermediate buy-sell steps cancel out.
So: just sum up all positive consecutive differences. If prices[i+1] > prices[i], add the difference to profit. Ignore negative differences (do not trade on down days).
Algorithm
- Initialize
profit = 0. - For each index
ifrom0ton - 2:- If
prices[i + 1] > prices[i]: addprices[i + 1] - prices[i]toprofit.
- If
- Return
profit.
flowchart LR
A(["prices = [7,1,5,3,6,4]"])
A --> a["day 0→1: 1-7=-6 → skip"]
a --> b["day 1→2: 5-1=+4 → profit+=4"]
b --> c["day 2→3: 3-5=-2 → skip"]
c --> d["day 3→4: 6-3=+3 → profit+=3"]
d --> e["day 4→5: 4-6=-2 → skip"]
e --> R(["profit=7"])
Solution
def maxProfit(prices):
profit = 0
for i in range(len(prices) - 1):
if prices[i + 1] > prices[i]:
profit += prices[i + 1] - prices[i]
return profit
print(maxProfit([7, 1, 5, 3, 6, 4])) # 7
print(maxProfit([1, 2, 3, 4, 5])) # 4
print(maxProfit([7, 6, 4, 3, 1])) # 0
Complexity
- Time:
O(n)— one pass - Space:
O(1)
Common Pitfalls
Confusing this with Best Time to Buy and Sell Stock I. In problem I, you can only make one transaction. Here, unlimited transactions are allowed. The greedy approach only works because you can trade as many times as you want.
Trying to track buy/sell days. You do not need to know exactly which days to buy and sell to compute the maximum profit. The sum-of-positive-differences trick gives the correct answer without tracking individual transactions.
Selling before buying. You must buy before you can sell. The consecutive-day trick handles this automatically — we only add gains from one day to the next, never going backwards in time.