121. Best Time to Buy and Sell Stock
Problem Statement: You are given daily prices for a stock. Buy on one day and sell on a later day to make the most profit. Return that profit, or
0if no profit is possible.
Input: prices = [7, 1, 5, 3, 6, 4]
Output: 5
Picture it
Walk forward through the days, and on each one ask a single question:
If I sold today, what is the most I could have made?
The answer depends on one thing only: the cheapest price seen before today. You would have bought then, because no earlier day was better and no later day is available to you yet.
So carry two numbers as you go. The cheapest price so far, and the best profit so far. Each day, work out today's profit against the cheapest, keep it if it beats the record, then see whether today is the new cheapest.
Nothing has to be remembered about the days in between.
How to think about it
Checking every pair of days is the direct reading of the problem and it is . The observation that collapses it is that the buy day is never a free choice: for any sell day, the best buy is simply the minimum before it, and that minimum is easy to carry forward.
The order inside the loop matters.
work out today's profit first, using the cheapest from BEFORE today
then update the cheapest to include today
Updating first would let the same day serve as both the buy and the sell, giving a profit of zero. That is harmless here but wrong in spirit, and it becomes a real bug in variants where same-day trading changes the answer.
A falling market needs no special case. The profit on every day comes out negative, never beats the starting record of zero, and the answer stays 0, which is exactly what the problem asks for.
Walking through the example
Take prices = [7, 1, 5, 3, 6, 4], with the cheapest starting at infinity and the best profit at 0.
- Day price
7. No cheaper price exists yet, so no profit. The cheapest becomes7. - Price
1. Selling at1after buying at7loses money, so the record stays0. The cheapest becomes1. - Price
5. Selling now makes5 - 1 = 4, a new record. - Price
3. Selling makes2, which does not beat4. - Price
6. Selling makes5, a new record. - Price
4. Selling makes3, no improvement.
The answer is 5, from buying at 1 and selling at 6.
The code
class Solution:
def maxProfit(self, prices: list[int]) -> int:
cheapest = float("inf")
best = 0
for price in prices:
# today's profit uses the cheapest price from before today
best = max(best, price - cheapest)
# only then does today become a candidate buy
cheapest = min(cheapest, price)
return best
Time and space complexity
Time:
One pass, with two comparisons per day. Testing every buy and sell pair would be .
Space:
Two numbers, whatever the length of the input.
Remember this
For any sell day the best buy is just the cheapest price before it, so carry that minimum and the best profit and never look back. Compute today's profit before folding today into the minimum, so one day cannot be both the buy and the sell. A market that only falls returns 0 with no special case. time, space.