Problem
You have a list of daily stock prices and can make as many buy/sell transactions as you want โ but you can hold at most one share at a time. Find the maximum total profit you can earn.
- Input:
prices = [7, 1, 5, 3, 6, 4] - Output:
7 - Explanation: Buy at 1 (day 2), sell at 5 (day 3) for profit 4; buy at 3 (day 4), sell at 6 (day 5) for profit 3; total = 7.
Counter-example: prices = [7, 6, 4, 3, 1] โ output 0 โ prices only fall, so no trade is profitable.
Intuition
Any valley-to-peak gain can be split into consecutive day-over-day gains without losing any total profit. Instead of finding the perfect buy and sell windows, you can simply collect every day where the price rises. This reduces the problem to a single linear scan with no state tracking at all.
Solution โ Greedy Day-Over-Day Scan
Scan adjacent day pairs and accumulate every positive price difference; skip days where the price falls.
- Initialize
total_profitto 0. - Loop through days starting from the second day (index 1).
- If today's price exceeds yesterday's, add the difference to
total_profit. - Return
total_profit.
1def maxProfit(prices: list[int]) -> int:
2 total_profit = 0
3 for i in range(1, len(prices)):
4 # every upward move is a profitable trade worth capturing
5 if prices[i] > prices[i - 1]:
6 total_profit += prices[i] - prices[i - 1]
7 return total_profitTime: O(n) โ single pass through the prices array.
Space: O(1) โ only a running total is stored.
Complexity Summary
| Approach | Time | Space | When to use |
|---|---|---|---|
| Greedy Day-Over-Day Scan | O(n) | O(1) | Any time unlimited transactions are permitted |
Common Mistakes
- Tracking
min_pricelike in Stock I โ Stock I needs the historical minimum because you get exactly one buy opportunity; here each transaction is independent so past price minimums are irrelevant and only the previous day matters. - Hunting for valley-peak pairs with nested loops โ finding local minima and maxima works but is unnecessarily complex; the greedy proves that the sum of all positive consecutive differences within a rising run equals the run's total valley-to-peak gain.
- Treating the problem as strict alternating buy/sell cycles โ you don't need to track a
holdingboolean or toggle between buy/sell modes; scanning for positive daily moves captures all profit without managing transaction state. - Starting the iteration at index 0 โ comparing
prices[i]withprices[i - 1]ati = 0accessesprices[-1]in Python (wraps to the last element, giving a wrong result) and throwsArrayIndexOutOfBoundsExceptionin Java; always start at index 1. - Returning a negative value when prices only fall โ an approach that blindly computes
prices.last - prices.firstwould return a negative profit; the greedy naturally returns 0 for a monotonically decreasing array since no conditionprices[i] > prices[i - 1]is ever true.
Related Problems
best-time-to-buy-and-sell-stockโ single transaction variant; requires tracking the running minimum price to find the best buy daybest-time-to-buy-and-sell-stock-iiiโ at most two transactions; requires DP with explicit state tracking for buy/sell countsbest-time-to-buy-and-sell-stock-with-cooldownโ same unlimited-transaction setup but a mandatory rest day after each sale changes the recurrencebest-time-to-buy-and-sell-stock-with-transaction-feeโ same greedy logic applies but each trade's gain is reduced by a fixed fee, merging adjacent small gains becomes optimalmaximum-subarrayโ shares the "accumulate every positive contribution and reset on loss" greedy mindset, applied to subarrays rather than day-over-day price moves