Back to the journalNOTES BY FAJAR
Algorithms3 min read

Leetcode - Best Time to Buy and Sell Stock Solution

Track the lowest price seen so far to find the best profit from one stock transaction.

In this article 3 sections

Choose one purchase day and one later sale day to get the largest positive price difference. My first solution checked every pair, which was O(n²). Tracking the lowest price seen so far reduces the scan to O(n).

The single transaction constraint

The input is an array prices, where prices[i] is the price on day i. I may buy once and sell once later, so the sell day must come after the buy day. A falling sequence produces no profit, and an empty or single day input also returns zero.

My initial thought was to check every possible pair of buy and sell days:

javascript
function maxProfitNaive(prices) {
  let maxProfit = 0;

  for (let i = 0; i < prices.length; i++) {
    for (let j = i + 1; j < prices.length; j++) {
      const profit = prices[j] - prices[i];
      if (profit > maxProfit) {
        maxProfit = profit;
      }
    }
  }

  return maxProfit;
}

The pairwise method is correct, but its O(n²) running time grows quickly with the number of days.

One pass and its invariant

I then tracked the minimum price seen so far and the best profit found at each day. The current price is the possible selling price, while minPrice represents the best legal buying price before it.

javascript
function maxProfit(prices) {
  let minPrice = Infinity; // Track the lowest price seen so far
  let maxProfit = 0; // Track the maximum profit found

  for (let i = 0; i < prices.length; i++) {
    // If current price is lower, update our minimum
    if (prices[i] < minPrice) {
      minPrice = prices[i];
    }
    // Otherwise, check if selling now gives better profit
    else if (prices[i] - minPrice > maxProfit) {
      maxProfit = prices[i] - minPrice;
    }
  }

  return maxProfit;
}

After day i, minPrice contains the smallest price in days 0 through i. The value of maxProfit is the best valid profit for those days. If the current price is lower, the algorithm updates minPrice for future sales. Otherwise, prices[i] - minPrice gives the best profit from a sale today. The value of maxProfit preserves the best result from earlier days.

Trace, Java implementation, and complexity

For [7, 1, 5, 3, 6, 4], the one pass state changes as follows:

javascript
const prices = [7, 1, 5, 3, 6, 4];
console.log(maxProfit(prices)); // Output: 5

The trace is:

  • Day 0: price is 7, minPrice becomes 7, profit is 0
  • Day 1: price is 1, minPrice becomes 1 (lower!), profit is still 0
  • Day 2: price is 5, minPrice is 1, profit = 5 - 1 = 4
  • Day 3: price is 3, minPrice is 1, profit = 3 - 1 = 2 (not better)
  • Day 4: price is 6, minPrice is 1, profit = 6 - 1 = 5 (better!)
  • Day 5: price is 4, minPrice is 1, profit = 4 - 1 = 3 (not better)

The best profit is 5, from buying at 1 and selling at 6.

The Java version keeps the same invariant:

java
public class StockProfit {
    public static int maxProfit(int[] prices) {
        int minPrice = Integer.MAX_VALUE;
        int maxProfit = 0;

        for (int i = 0; i < prices.length; i++) {
            if (prices[i] < minPrice) {
                minPrice = prices[i];
            } else if (prices[i] - minPrice > maxProfit) {
                maxProfit = prices[i] - minPrice;
            }
        }

        return maxProfit;
    }

    public static void main(String[] args) {
        int[] prices = {7, 1, 5, 3, 6, 4};
        System.out.println(maxProfit(prices)); // Output: 5
    }
}

My first pairwise solution was intuitive, but it tracked more information than necessary. The one pass version uses O(n) time and O(1) extra space. It also handles a decreasing array because maxProfit remains zero while minPrice keeps moving down.

The main question is what state makes each future decision possible. Here, the minimum price and maximum profit are enough, so the pairwise search is unnecessary.

FILED UNDER

THANKS FOR READING

Did this resonate?

A reaction or a conversation is always welcome.

Loading reactions…

Pass it along

Loading comments...

Related posts

All writing