Best Time to Buy and Sell Stock — One-Pass Min Tracker
Walk through Best Time to Buy and Sell Stock. We go from the quadratic brute force to a clean one-pass solution tracking the running minimum.
What you'll learn
- ✓Brute-force approach and its complexity
- ✓Optimal approach with intuition
- ✓Edge cases that trip people up
- ✓How to talk through it in an interview
- ✓Related problems to follow up with
Prerequisites
- •Basics from arrays introduction and Big O notation
Best Time to Buy and Sell Stock looks like a trick question the first time you see it, then becomes a one-liner once you see the pattern. The lesson it teaches, tracking a running extreme while sweeping the array, comes up constantly.
The Problem
You are given an array prices where prices[i] is the price of a stock on day i. You want to maximize profit by choosing a single day to buy and a different later day to sell. Return the maximum profit; if no profit is possible, return 0.
Example:
Input: prices = [7, 1, 5, 3, 6, 4]
Output: 5
Explanation: Buy on day 2 (price 1) and sell on day 5 (price 6).
Buying after selling is not allowed, which is the only real constraint.
Intuition
The brute force tries every pair where the buy day comes before the sell day. That is O(n^2) and times out on large inputs.
The key insight: at each day i, the best sell price is just prices[i], and the best profit you could achieve by selling today is prices[i] - min(prices[0..i-1]). So we only need to track the minimum price seen so far. As we sweep the array left to right, we keep a running minimum and a running best profit. One pass, two scalars.
Explanation with Example
Walk through prices = [7, 1, 5, 3, 6, 4].
- Start:
min_price = 7,best = 0. - Day 1, price 1. Profit if sell = 1 - 7 = -6. best stays 0. Update min_price to 1.
- Day 2, price 5. Profit = 5 - 1 = 4. best becomes 4. min_price stays 1.
- Day 3, price 3. Profit = 3 - 1 = 2. best stays 4.
- Day 4, price 6. Profit = 6 - 1 = 5. best becomes 5.
- Day 5, price 4. Profit = 4 - 1 = 3. best stays 5.
Return 5. Order matters: compute the candidate profit before updating min_price, otherwise you would be selling and buying on the same day.
day 0 1 2 3 4 5
price 7 1 5 3 6 4
min 7 1 1 1 1 1
profit 0 0 4 2 5 3
^
best = 5 Code
def max_profit(prices):
if not prices:
return 0
min_price = prices[0]
best = 0
for price in prices[1:]:
best = max(best, price - min_price)
min_price = min(min_price, price)
return bestclass Solution {
public int maxProfit(int[] prices) {
if (prices.length == 0) return 0;
int minPrice = prices[0];
int best = 0;
for (int i = 1; i < prices.length; i++) {
best = Math.max(best, prices[i] - minPrice);
minPrice = Math.min(minPrice, prices[i]);
}
return best;
}
}class Solution {
public:
int maxProfit(vector<int>& prices) {
if (prices.empty()) return 0;
int minPrice = prices[0];
int best = 0;
for (size_t i = 1; i < prices.size(); ++i) {
best = max(best, prices[i] - minPrice);
minPrice = min(minPrice, prices[i]);
}
return best;
}
};Edge Cases
- Strictly decreasing prices like
[7, 6, 4, 3, 1]. No profitable trade exists. Return 0. - Single-element array. No trade possible. Return 0.
- Empty array. Defensive check at the top.
- All equal prices. Profit is 0.
- Integer overflow. Not a Python concern, but in C++ or Java you should think about it.
Complexity Analysis
- Time: O(n). One pass.
- Space: O(1). Two scalars regardless of input size.
This is as efficient as the problem allows; you must look at every price at least once.
How to Explain It in an Interview
- Restate the problem and confirm: you can only buy once and sell once, and sell day must come after buy day.
- Mention the brute force in one sentence to anchor complexity.
- Explain the key insight: “For each day, I only care about the minimum I have seen so far. The best profit ending at this day is price minus running min.”
- Code it and emphasize the order: compute profit first, then update min.
- State O(n) time and O(1) space.
- Mention the multi-transaction variant if asked for an extension.
Related Problems
- Best Time to Buy and Sell Stock II
- Best Time to Buy and Sell Stock III
- Best Time to Buy and Sell Stock IV
- Best Time to Buy and Sell Stock with Cooldown
- Maximum Subarray
For the array fundamentals that make this trivial, see arrays common operations.
Wrap up
The pattern here, “sweep once, maintain a running extreme, derive the answer at each step”, is one of the most reusable ideas in array problems. Maximum Subarray uses the same skeleton with a running sum instead of a running min. Master it on this problem and a dozen others fall out for free.
Related articles
- DSA Find Minimum in Rotated Sorted Array — Binary Search
Solve Find Minimum in Rotated Sorted Array in logarithmic time with a modified binary search. Learn the pivot-finding invariant, edge cases, and how to extend the pattern to related problems.
- DSA Maximum Product Subarray — Tracking Min and Max
Solve Maximum Product Subarray in linear time by tracking running min and max. Learn why negative numbers flip the role of min and max and see clean code.
- DSA Reverse String — Two-Pointer In-Place Solution
Solve the Reverse String problem in place using the two-pointer technique. Walkthrough, complexity analysis, edge cases, and clean Java, Python, and C++ implementations.
- DSA Rotate Array — The Triple-Reverse Trick
Rotate an array by k steps in O(1) extra space using the triple-reverse trick. Compare it with the extra-array approach and learn why this pattern keeps showing up.