LeetCode #122 Medium

Best Time to Buy and Sell Stock II

You may buy and sell a stock as many times as you like, holding at most one share at a time. Return the maximum profit.

greedyarraydynamic-programming
Open on LeetCode ↗
02

Intuition

With unlimited transactions there is no need to identify the 'right' valleys and peaks. Any profitable hold from day i to day j yields exactly the same money as buying and selling on every single day in between — the intermediate prices cancel telescopically. So the maximum profit is simply the sum of every positive day-to-day change. Days where the price falls are avoided by holding nothing, costing nothing.

How to spot this pattern

Unlimited transactions means you can capture every upward move independently. Summing all positive day-to-day differences is equivalent to buying at each valley and selling at each peak — the telescoping sum over a rising run equals the single trade across it.

03

Approach

1

See why peak-and-valley detection is unnecessary

The instinct is to find each local minimum, buy, find the next local maximum, sell. That works, but consider prices 1, 5 versus 1, 3, 5. Buying at 1 and selling at 5 earns 4. Buying at 1 selling at 3, then buying at 3 selling at 5, also earns 2 + 2 = 4. The sums are identical because the intermediate price appears once positively and once negatively. So a long hold and a chain of one-day holds are interchangeable.

2

Reduce it to summing positive deltas

If every profitable hold can be decomposed into consecutive single-day holds, then the total profit is the sum of prices[i] - prices[i-1] over all days where that difference is positive. Negative differences are simply skipped — on a falling day we hold no stock and lose nothing. No state, no lookahead, one pass.

3

Note the DP formulation, and why the greedy is preferred here

The general framing tracks two states per day: hold (maximum profit while owning a share) and free (maximum while owning none), with hold = max(hold, free - price) and free = max(free, hold + price). That machinery is required for the k-transaction and cooldown variants. For unlimited transactions it provably reduces to the delta sum, so state the DP to show you know the general pattern, then implement the one-liner.

04

Solution & live demo

1class Solution:
2 def maxProfit(self, prices):
3 profit = 0
4 for i in range(1, len(prices)):
5 if prices[i] > prices[i - 1]:
6 profit += prices[i] - prices[i - 1]
7 else:
8 pass
9 return profit
05

Common pitfalls

Hunting for explicit peaks and valleys

✗ Wrong
find each local min, then the next local max, add the difference
✓ Right
if prices[i] > prices[i-1]:
    profit += prices[i] - prices[i-1]

Peak-and-valley detection needs careful handling of plateaus and the final element. Summing positive deltas gives the identical total with no boundary cases, because consecutive gains telescope into the full rise.

Applying the single-transaction solution

✗ Wrong
return max(prices) - min(prices)
✓ Right
profit += prices[i] - prices[i - 1]

That's the Stock I answer and it also breaks when the maximum precedes the minimum. Here you may trade repeatedly, so a zigzag price series yields far more than any single trade.

Adding negative differences

✗ Wrong
profit += prices[i] - prices[i - 1]
✓ Right
if prices[i] > prices[i - 1]:
    profit += prices[i] - prices[i - 1]

Without the guard the sum telescopes to prices[-1] - prices[0], the profit of holding throughout. Skipping the down days is exactly what models selling before each decline.

06

Edge cases

Strictly decreasing prices

No delta is positive, so the profit is 0 — the correct answer, since making no trade is always allowed.

Strictly increasing prices

Every delta is positive and their sum telescopes to prices[-1] - prices[0], matching a single buy-and-hold.

Single day

The loop never runs and the profit is 0 — you cannot buy and sell on the same day.

Flat stretches

A zero delta contributes nothing and is correctly ignored.

07

Complexity

Time
O(n)
Space
O(1)
One pass, one accumulator. The two-state DP is also O(n) but carries state the unlimited-transaction case does not need.