DSA Trainer
← All patterns
Pattern

Tracking Minimum Pattern

Remember the best opportunity you've passed. Don't rescan to find it.

Quick Summary

Best used when

  • You need the best value seen before the current position
  • You need to compute the maximum difference between two positions (earlier minus later, or later minus earlier)
  • The brute force would fix one element and scan everything before it with a nested loop
  • One extra variable can replace all backward-scanning

Clue words in the problem

buy and sellminimum so farprofitmaximum differencebest opportunity

Complexity gain

O(n²) pair comparison → O(n) single pass with running minimum

Why this pattern matters for LeetCode

The brute force tries every buy/sell pair — O(n²). Tracking Minimum is O(n): carry the cheapest price seen so far, and at each price compute what the profit would be if you sold today. One variable eliminates the need to scan backward. The critical order matters: you must update the minimum BEFORE computing profit, because you can't sell before you buy.

What the Tracking Minimum pattern is

The tracking minimum (or maximum) pattern maintains a running best value as you scan forward. Instead of comparing every pair with a nested loop, you remember the smallest (or largest) element seen so far and compute the answer relative to it at each step. This collapses O(n²) pair comparisons into a single O(n) pass. The insight: you never need to look backward — you already have the optimal historical value stored in one variable.

Reach for Tracking Minimum when you catch yourself thinking…

These are the internal questions that signal this pattern.

Do I need the best value seen so far at each position in the array?
Am I comparing the current element to something from earlier in the array?
Would the brute force fix one element and scan everything before it?
Can I carry a single extra variable forward and avoid re-scanning?

Beginner mental model

Imagine checking every day's weather to find the coldest morning so far this month. You don't re-read every previous day's log — you just keep a running 'record low.' When tomorrow comes, compare and update if today was colder. That record low is the tracked minimum. For buy/sell stock: as you walk through prices, you track the cheapest price you could have bought at. At each price, compute the profit if you sold today. Update the answer if it's better.

Ready to practice Tracking Minimum?

DSA Trainer gives you guided hints, not answers, so you build real intuition.

When to use Tracking Minimum

  • Maximum profit from buy-sell stock (classic Tracking Minimum)
  • Maximum difference between two elements where the smaller comes first
  • Finding the best 'buy' before the current 'sell' in any single-pass problem
  • Any problem where you need the running min or max up to the current position

When NOT to use Tracking Minimum

  • You need to track the global maximum — that's a simpler running max pattern
  • The problem allows multiple transactions — a different DP or greedy approach is needed
  • The minimum doesn't need to come before the maximum — Two Pointers or sorting may apply
  • You need the minimum of a window, not the overall minimum so far — use a deque (monotonic queue)

Better alternative: In those cases, Kadane's Algorithm (for subarray sums) or a monotonic deque (for windowed minimums) may be more appropriate.

JavaScript code template

Best Time to Buy and Sell Stock — O(n) time, O(1) space

function maxProfit(prices) {
  let minPrice = Infinity;
  let maxProfit = 0;

  for (const price of prices) {
    // Update minPrice FIRST — you must buy before you sell
    minPrice = Math.min(minPrice, price);

    // Compute profit if you sold at today's price
    const profit = price - minPrice;

    // Update the best profit seen so far
    maxProfit = Math.max(maxProfit, profit);
  }

  return maxProfit;
}

minPrice tracks the cheapest price seen before or at the current day. Update it first — this ensures you never use today's price as both the buy and sell. Then compute profit assuming you sell at the current price. Update maxProfit if this is better than any previous opportunity. If prices only ever decrease, maxProfit stays 0 (you simply don't transact).

Step-by-step thinking process

Walk through this in your head before writing code.

  1. 1Initialize minSoFar = Infinity and maxDiff = 0.
  2. 2Loop through each value in the array.
  3. 3Update minSoFar = Math.min(minSoFar, current) — do this FIRST.
  4. 4Compute the current difference: current - minSoFar.
  5. 5Update maxDiff = Math.max(maxDiff, currentDiff) if this is the best you've seen.
  6. 6Return maxDiff after the loop.

LeetCode-style problems that use this pattern

Practice on DSA Trainer with guided hints: no spoilers, just nudges.

Coming soon

  • Best Time to Buy and Sell Stock II

    Multiple transactions allowed — greedy: take every upward slope.

    Coming soon
  • Maximum Difference Between Increasing Elements

    Same pattern as buy/sell — track the running minimum and compute the max difference where smaller comes first.

    Coming soon

Common mistakes beginners make

  • Updating maxProfit before minPrice — this lets you compute profit using today's price as both buy and sell, which is invalid.
  • Initializing minPrice to 0 instead of Infinity — with 0, prices like [3, 2, 1] produce a negative difference and wrong profits.
  • Returning a negative profit — if prices only decrease, the correct answer is 0 (you don't trade). maxProfit initialized to 0 handles this.
  • Nested loop instinct: comparing every pair of buy/sell days is O(n²). The running minimum means you never need to look backward.

Tracking Minimum vs Kadane's vs Sliding Window

Choose the right tool for the job.

PatternUse when…
Tracking MinimumYou need the best single 'past value' relative to the current position — one running variable
Kadane's AlgorithmYou're finding the maximum sum of a contiguous subarray — extend-or-restart decision at each step
Sliding WindowYou're tracking a contiguous range and its internal state — the window expands and shrinks based on a constraint

Time and space complexity

Time complexity

O(n)

Space complexity

O(1)

One pass through the array — each price is visited once. Two variables (minPrice and maxProfit) use O(1) space. No extra arrays, no nested loops, no backward scanning.

Ready to practice Tracking Minimum?

DSA Trainer gives you guided hints, not answers, so you build real intuition.

Frequently asked questions

Why must I update minPrice before computing profit?
Because you can't sell before you buy. If you compute profit first using today's price, and then update minPrice to today's price, you might be subtracting today's price from itself — profit of 0 at best, or using a future price as the 'buy' date. Update minPrice first to ensure the buy always comes before the sell.
Why initialize minPrice to Infinity and not 0?
Because 0 is not a valid price floor — real prices are all positive. If you initialize to 0, the first Math.min(0, prices[0]) keeps minPrice at 0, and you compute prices[0] - 0 as the profit, which is wrong. Infinity ensures the first real price always wins and becomes the initial minPrice.
How is Tracking Minimum different from Kadane's Algorithm?
Kadane's tracks a running sum and decides at each element whether to extend or restart the subarray. Tracking Minimum keeps a single 'best historical value' (minimum price) and computes a difference (profit) at each step. They solve different shaped problems: Kadane's for contiguous sums, Tracking Minimum for best pair with the smaller value coming first.
Why is this O(n) when the brute force is O(n²)?
The brute force has a nested loop: for each sell day, scan all previous days for the best buy. The inner loop is O(n) per sell day — O(n²) total. Tracking Minimum replaces the inner loop with one O(1) operation: compare the current price to a pre-computed running minimum. You get the same result in O(n) time because the running minimum captures everything the inner loop would have scanned.

Explore other patterns