ARRAYS · GREEDY
LeetCode 121 · Easy

Best Time to Buy and Sell Stock — O(n) Python Solution Explained

📚 DSA · Arrays · Greedy ⏱ 8 min read 🐍 Python 🎯 Interview Ready

To maximize profit from a single stock transaction, scan prices once. Track the minimum price seen so far and at every step compute current price − min price. Update the max profit if this value is higher. This runs in O(n) time and O(1) space.

01 Introduction

Imagine you could see Apple's stock prices for the past week — $180, $140, $155, $130, $170, $160. You can buy once and sell once. Which days do you pick to make the most money?

This is the Best Time to Buy and Sell Stock problem — one of the most commonly asked questions in coding interviews at Google, Amazon, Microsoft, and every major tech company. It looks simple on the surface, but beginners keep getting it wrong because they jump straight to checking every possible pair of days.

In this guide you'll understand exactly why the naive approach fails, how the optimal single-pass approach works, and how to explain it confidently in any interview.

Why beginners struggle They think "check all pairs" is fine. For 10 elements it is. For 100,000 elements? Your solution will time out. This problem rewards clear algorithmic thinking.

02 Problem Statement

You are given an array prices where prices[i] is the price of a stock on day i. You want to maximize your profit by choosing one day to buy and a later day to sell. Return the maximum profit possible. If no profit is possible, return 0.

Example 1

# Input
prices = [7, 1, 5, 3, 6, 4]

# Output
5

# Explanation: Buy on day 2 (price=1), sell on day 5 (price=6). Profit = 6-1 = 5

Example 2

# Input
prices = [7, 6, 4, 3, 1]

# Output
0

# Explanation: Prices only go down. No transaction is beneficial.

Input / Output Format

FieldTypeDescription
pricesList[int]Stock prices for each day
OutputintMaximum profit (0 if no profit)

Constraints

  • 1 ≤ prices.length ≤ 10⁵
  • 0 ≤ prices[i] ≤ 10⁴
  • You must buy before you sell (not on the same day)
  • Only one transaction allowed

03 Real World Explanation

Think about how stock traders actually think. Their core goal is to buy low, sell high. But the catch is timing — you can only sell after you buy, not before.

Here's where beginners get confused in real trading too: they see a high price on day 3 and a low price on day 5. They think "sell on day 3, buy on day 5." That's short-selling, which is a completely different concept. In this problem, you always buy first, sell second.

Real Trading Insight The optimal strategy in one transaction is to hold the stock from its historical minimum to the highest point after that minimum. The algorithm essentially simulates this automatically.

This same logic applies to cryptocurrency trading — finding the right entry point is everything. If you bought Bitcoin at $15,000 and sold at $60,000, your profit is $45,000. This algorithm would find that exact pair automatically.

04 Naive Approach — Brute Force O(n²)

The first idea most beginners have: for every possible buying day, check every possible selling day after it. Track the pair that gives maximum profit.

def max_profit_brute(prices):
    n = len(prices)
    max_profit = 0
    
    for i in range(n):           # buy day
        for j in range(i+1, n):   # sell day (must be after buy)
            profit = prices[j] - prices[i]
            max_profit = max(max_profit, profit)
    
    return max_profit
Why This Fails With n = 100,000, this runs ~5 billion comparisons. Even at 10⁹ operations per second, that's 5 seconds. LeetCode will time out. You need O(n).

05 Optimal Approach — Single Pass O(n)

The insight is elegant. You don't need to check every pair. You just need two variables as you scan left to right:

  • min_price — the lowest price seen so far (best time to have bought)
  • max_profit — the highest profit achievable so far

For each price: if it's lower than min_price, update min_price. Otherwise, see if selling now beats your current best profit.

Core Insight For any selling day j, the best buying day is always the day with the minimum price before j. So we just track that minimum as we go.

06 Key Intuition

Why does tracking the minimum work? Because profit = sell_price − buy_price. To maximize profit for a fixed sell day, you want the smallest possible buy price — and that's always the minimum price seen so far.

Common Misunderstanding

Some students think: "What if I update min_price but then I miss a higher profit?" That can't happen — because when you update min_price to a new low, you're making future profits potentially bigger, not smaller. A lower buy price can only help.

Why we don't reset max_profit when updating min_price

Because max_profit already holds the best answer we've seen so far. We're just potentially improving future profits. The overall maximum is preserved.

07 Algorithm Flowchart

START: Initialize min_price = ∞, max_profit = 0
Iterate through each price in array
Is price < min_price?
YES
Update min_price = price
NO
profit = price − min_price
Update max_profit if profit > max_profit
More prices remaining?
RETURN max_profit

08 Python Solution

def max_profit(prices):
    """
    Find maximum profit from a single buy-sell transaction.
    
    Args:
        prices: List of stock prices indexed by day
    Returns:
        Maximum achievable profit (0 if no profit possible)
    """
    if not prices or len(prices) < 2:
        return 0
    
    min_price = float('inf')   # Start with infinity (any price beats this)
    max_profit = 0             # At worst, we make zero (don't trade)
    
    for price in prices:
        if price < min_price:
            min_price = price            # Found a cheaper buying point
        else:
            profit = price - min_price   # What if we sell today?
            max_profit = max(max_profit, profit)  # Keep the best
    
    return max_profit


# --- Input Handling ---
if __name__ == "__main__":
    n = int(input("Number of days: "))
    prices = list(map(int, input("Prices (space-separated): ").split()))
    print(f"Maximum Profit: {max_profit(prices)}")

09 Dry Run — Step by Step

Input: [7, 1, 5, 3, 6, 4]

Day Price min_price Current Profit max_profit Action
0770Set min = 7
1110New min found (1 < 7)
2515−1 = 44Profit updated
3313−1 = 24No improvement
4616−1 = 55Best profit! ✓
5414−1 = 35No improvement
Result Buy on Day 1 (price = 1), Sell on Day 4 (price = 6). Maximum Profit = 5.

10 Price Visualization

Stock Price vs Day — [7, 1, 5, 3, 6, 4]
Buy point (min) Sell point (max profit) Other days

11 Time & Space Complexity

O(n)

Time Complexity

We scan the array exactly once. Every element is visited one time.

O(1)

Space Complexity

Only two variables used — min_price and max_profit. No extra arrays.

ApproachTimeSpaceVerdict
Brute ForceO(n²)O(1)Too slow for large input
Single Pass (Optimal)O(n)O(1)Interview-ready ✓

12 Test Cases

Test 1 — Increasing Prices
Input: [1, 2, 3, 4, 5]
Output: 4
Buy day 0, sell day 4
Test 2 — Decreasing Prices
Input: [5, 4, 3, 2, 1]
Output: 0
No profitable trade possible
Test 3 — Single Element
Input: [7]
Output: 0
Can't buy and sell on same day
Test 4 — Standard Case
Input: [7,1,5,3,6,4]
Output: 5
Classic example
Test 5 — All Same
Input: [3, 3, 3, 3]
Output: 0
No profit, prices flat
Test 6 — Two Elements
Input: [2, 5]
Output: 3
Minimum valid input with profit

13 Common Interview Questions

Q1 Can you solve this in O(n) time and O(1) space?
Q2 What happens if the array has only one element?
Q3 What if all prices are decreasing — what should you return?
Q4 How would you extend this if two transactions were allowed? (LeetCode 123)
Q5 Why can't you sell before you buy in this problem?
Q6 Why do you initialize min_price to infinity instead of prices[0]?

14 Mistakes Beginners Make

Selling before buying

Forgetting that sell index must be greater than buy index. Always move left-to-right.

Returning negative profit

If no profit is possible, return 0, not a negative number. Initialize max_profit = 0, not -infinity.

Not updating min_price correctly

Some students only check profit and never update min_price when they find a lower value. This breaks the entire logic.

Using max of array minus min of array

This looks smart but it's wrong. The minimum might come after the maximum — meaning you'd have to sell before buying. Always ensure min appears before max in time.

15 Conclusion

The Best Time to Buy and Sell Stock problem is a perfect example of how simple thinking leads to elegant solutions. Instead of brute-forcing all pairs in O(n²), you ask one smarter question at each step: "If I sell today, what's the best price I could have bought at?"

Track the historical minimum, compute the current profit, update the answer. That's it. Two variables, one loop, O(n) time, O(1) space.

Key Takeaway This problem teaches you the power of single-pass greedy thinking — a pattern that appears in dozens of other DSA problems. Master this and the rest becomes easier.

16 Frequently Asked Questions

What is the Best Time to Buy and Sell Stock problem? +
It's LeetCode problem 121. Given a price array, find the maximum profit you can make by buying on one day and selling on a later day. Only one transaction is allowed.
Why can't I just subtract the minimum from the maximum in the array? +
Because the minimum price might appear after the maximum. You must buy before you sell. Simply finding max - min can give you an invalid trade where you'd need to go back in time.
What if no profit is possible? +
Return 0. The problem guarantees that doing nothing (not trading) is always an option, and that earns zero profit. Never return a negative value.
What is the time complexity of the optimal solution? +
O(n) time and O(1) space. You scan the array exactly once and use only two variables — no extra arrays or nested loops needed.
How is this related to real stock trading? +
In real markets, traders aim to buy at the historical low and sell at a high point afterward. This algorithm essentially automates that decision for any historical price data — crypto, stocks, commodities alike.
What are the variations of this problem in interviews? +
LeetCode has a full series: Problem 121 (one transaction), 122 (unlimited transactions), 123 (two transactions), 188 (k transactions), and 309 (with cooldown). All build on the same foundational idea.
#best-time-buy-sell-stock #stock-buy-sell-python #max-profit-algorithm #DSA-interview #arrays #greedy #leetcode-121 #single-transaction #O(n)-solution