Faisalaffan Blog
Faisalaffan Blog
Engineering5 min read

Best Time to Buy and Sell Stock: From Brute Force to One-Pass O(n)

Master the classic coding interview problem 'Best Time to Buy and Sell Stock' with step-by-step explanation โ€” from the naive brute force approach, recognizing patterns, to the optimal one-pass O(n) solution using sliding window / two-pointer technique. Complete with array visualization, complexity analysis, and the intuition behind every decision.

Faisal Affan
Faisal Affan
Published
Best Time to Buy and Sell Stock: From Brute Force to One-Pass O(n)

The secret behind many array problems: "What if I track the minimum so far while scanning?" โ€” this pattern shows up everywhere, from stock trading to rainwater trapping.

Problem Statement

You are given an array prices where prices[i] is the price of a given stock on the i-th day. Find the maximum profit from a single transaction โ€” buy on one day, sell on a later day. If no profit is possible (prices only decrease), return 0.

Constraints:

  • 1 <= prices.length <= 10โต
  • 0 <= prices[i] <= 10โด

Examples from the prompt:

Plaintext
Input:  prices = [7, 1, 5, 3, 6, 4]
Output: 5

Buy on day 2 (price = 1), sell on day 5 (price = 6), profit = 6 - 1 = 5.

Plaintext
Input:  prices = [7, 6, 4, 3, 1]
Output: 0

No transaction yields profit โ€” prices only go down.

Initial Intuition โ€” Brute Force

First thought: try every possible buy-sell pair.

Go
func maxProfit(prices []int) int {
    maxProfit := 0
    n := len(prices)
    for buy := 0; buy < n; buy++ {
        for sell := buy + 1; sell < n; sell++ {
            profit := prices[sell] - prices[buy]
            if profit > maxProfit {
                maxProfit = profit
            }
        }
    }
    return maxProfit
}

Straightforward logic: for each buy day, try every sell day after it. Compute profit, track the maximum.

Complexity: O(nยฒ) โ€” full nested loop. For n = 10โต, this runs ~10ยนโฐ iterations. Won't pass.

Key Observation

Re-examine the example: [7, 1, 5, 3, 6, 4]

For any candidate sell day, maximum profit comes from buying at the lowest price seen before that day.

Day Price Min price before today Profit if sell today
1 7 N/A (can't sell yet) -
2 1 7 1 - 7 = -6 โ†’ max(previous, 0) = 0
3 5 1 (updated after seeing 1) 5 - 1 = 4
4 3 1 3 - 1 = 2
5 6 1 6 - 1 = 5
6 4 1 4 - 1 = 3

Maximum profit: max(0, 4, 2, 5, 3) = 5. Matches expected output.

Pattern: Track Minimum While Scanning

From the table above, we realize: no nested loop needed. Just one pass left to right, maintaining two values:

  1. Lowest price seen so far (min_price)
  2. Maximum profit achievable if selling at the current price (max_profit)

At each step i:

  • Profit if sell now = prices[i] - min_price
  • Update max_profit if this profit is larger
  • Update min_price if prices[i] is smaller than min_price

Optimal Solution โ€” One-Pass O(n)

Go
func maxProfit(prices []int) int {
    minPrice := math.MaxInt32
    maxProfit := 0

    for _, price := range prices {
        if price < minPrice {
            minPrice = price
        } else {
            profit := price - minPrice
            if profit > maxProfit {
                maxProfit = profit
            }
        }
    }

    return maxProfit
}

Or a more concise version:

Go
func maxProfit(prices []int) int {
    minPrice := math.MaxInt32
    maxProfit := 0

    for _, price := range prices {
        minPrice = min(minPrice, price)
        maxProfit = max(maxProfit, price-minPrice)
    }

    return maxProfit
}

What about the no-profit case? If prices only decrease (example 2: [7, 6, 4, 3, 1]), then price - min_price is always negative. But max_profit starts at 0, and max(0, negative) = 0. So it returns 0 โ€” matching the requirement.

Visualization

Plaintext
prices = [7, 1, 5, 3, 6, 4]

i=0: price=7  โ†’ min_price=7    profit=N/A   max_profit=0
i=1: price=1  โ†’ min_price=1    profit=N/A   max_profit=0
i=2: price=5  โ†’ min_price=1    profit=4     max_profit=4  โœ“
i=3: price=3  โ†’ min_price=1    profit=2     max_profit=4
i=4: price=6  โ†’ min_price=1    profit=5     max_profit=5  โœ“ (new max!)
i=5: price=4  โ†’ min_price=1    profit=3     max_profit=5

Return 5

Complexity

Aspect Value
Time O(n) โ€” single array traversal
Space O(1) โ€” only two variables (min_price, max_profit)

For n = 10โต, this solution completes in <1ms in any language.

Why This Pattern Matters

The "track minimum from the left while scanning" pattern is a building block for many problem variants:

  • Best Time to Buy and Sell Stock II โ€” unlimited transactions allowed
  • Best Time to Buy and Sell Stock III โ€” at most two transactions
  • Trapping Rain Water โ€” track max from left and right
  • Maximum Subarray (Kadane) โ€” track current_sum and max_sum

All stem from the same idea: maintain optimal state from data already passed, update state as you move forward.

Key Takeaway

Best profit comes from buying at the lowest price seen so far and selling at the current price. Track both in one pass.

This problem teaches that brute force can crumble with a single simple observation. Always ask before writing a nested loop: "What do I actually need to remember from the data I've already seen?"

Related stories

Engineering
Engineering
Integer to Roman: The Greedy Mapping That Always Shows Up in Interviews

Integer to Roman: The Greedy Mapping That Always Shows Up in Interviews

Breaking down the integer to Roman numeral conversion problem โ€” from basic Roman numeral rules, the subtractive notation pitfalls (IV, IX, XL...), to a clean, interview-ready greedy O(1) solution. Complete with mapping table, step-by-step visualization, and why this approach is optimal given the 1-3999 constraint.
Faisal Affan
Faisal Affan
Published
Engineering
Services I've Handled โ€” Full-Stack Engineering, Architecture & Product Strategy

Services I've Handled โ€” Full-Stack Engineering, Architecture & Product Strategy

A comprehensive list of professional services I've delivered across multiple industries: IoT fleet management, fintech core banking integration, cyber insurance platforms, education technology, and enterprise digital transformation. Each service backed by real production systems still running today.
Faisal Affan
Faisal Affan
Published
Engineering
Portfolio Strategy by Career Level โ€” Junior to CTO

Portfolio Strategy by Career Level โ€” Junior to CTO

Your portfolio should reflect your seniority level, not just list every project you've touched. Junior engineers sell potential and fundamentals. Senior engineers sell depth and architecture. Staff engineers sell leverage. CTOs sell business outcomes. Here's exactly what to put in your portfolio at each level โ€” with concrete examples and a universal format you can use today.
Faisal Affan
Faisal Affan
Published
Engineering
Modern AI Architecture: End-to-End

Modern AI Architecture: End-to-End

From the first user query to the response stored in the database. A complete guide to layers, tools, request flow, learning roadmap, and real-world production implementation โ€” including the newly released Google ADK.
Faisal Affan
Faisal Affan
Published