LeetCode Problem: Best Time to Buy and Sell Stock
Difficulty: Easy
Topics: Array, Greedy, Dynamic Programming
Series: LeetCode Interview Preparation — From Beginner to Expert
After learning Two Sum, it is time to learn another pattern that appears constantly in coding interviews:
Track the best opportunity you've seen so far while scanning the array once.
LeetCode's Best Time to Buy and Sell Stock looks like a simple stock-market problem, but it teaches an extremely important interview technique:
Maintain a running minimum and calculate the best answer at every step.
You are given an array prices where:
prices[i]represents the price of a stock on day i.
You want to choose:
Your goal is to maximize your profit.
If you cannot make any profit, return:
0Input:
prices = [7, 1, 5, 3, 6, 4]
Output:
5Why?
Buy at:
1and sell at:
6Profit:
6 - 1 = 5There is one critical constraint:
You must buy before you sell.
For example:
[7, 1, 5]You cannot buy at 5 and sell at 1.
The order matters.
This is what makes the problem more interesting than simply finding the largest difference between two numbers.
The simplest solution is to try every possible buying day and every possible selling day.
For every pair:
buy day < sell daycalculate:
profit = selling price - buying priceand keep the maximum.
def maxProfit(prices):
max_profit = 0
for i in range(len(prices)):
for j in range(i + 1, len(prices)):
profit = prices[j] - prices[i]
max_profit = max(max_profit, profit)
return max_profitThis solution works.
But there is a problem.
We are checking almost every possible pair.
If there are n days:
Time Complexity: O(n²)
Space Complexity: O(1)For a small input, that's fine.
But with millions of prices, checking every combination becomes expensive.
Can we solve it in one pass?
Yes.
Imagine we're currently on day i.
We want to sell today.
What is the best possible profit?
Simple:
Today's Price - Lowest Price Before TodaySo we don't actually need to remember every previous price.
We only need:
minimum price seen so farand:
maximum profit seen so farThat's the entire trick.
We'll maintain two variables:
min_price
max_profitInitially:
min_price = infinity
max_profit = 0Then scan the array from left to right.
For every price:
Update the cheapest buying price:
min_price = min(min_price, price)Calculate today's possible profit:
profit = price - min_priceUpdate the best profit:
max_profit = max(max_profit, profit)That's it.
def maxProfit(prices):
min_price = float('inf')
max_profit = 0
for price in prices:
min_price = min(min_price, price)
profit = price - min_price
max_profit = max(max_profit, profit)
return max_profitConsider:
prices = [7, 1, 5, 3, 6, 4]We'll start with:
min_price = ∞
max_profit = 0Current price:
7Cheapest price so far:
7Potential profit:
7 - 7 = 0So:
min_price = 7
max_profit = 0Current price:
1We found a cheaper buying opportunity.
min_price = 1Profit:
1 - 1 = 0So:
max_profit = 0Current price:
5Minimum price remains:
1Potential profit:
5 - 1 = 4Therefore:
max_profit = 4Minimum price:
1Potential profit:
3 - 1 = 2Our previous profit was better:
max_profit = 4Minimum price:
1Potential profit:
6 - 1 = 5New maximum:
max_profit = 5Potential profit:
4 - 1 = 3No improvement.
Final answer:
5| Day | Price | Minimum Price | Potential Profit | Maximum Profit |
|---|---|---|---|---|
| 1 | 7 | 7 | 0 | 0 |
| 2 | 1 | 1 | 0 | 0 |
| 3 | 5 | 1 | 4 | 4 |
| 4 | 3 | 1 | 2 | 4 |
| 5 | 6 | 1 | 5 | 5 |
| 6 | 4 | 1 | 3 | 5 |
Final answer:
5Suppose today's price is:
10To maximize today's profit, we want the cheapest possible price before today.
Suppose we've already seen:
7
5
3
8The best buying price is:
3Therefore:
profit = 10 - 3
= 7There is no reason to remember the other buying prices.
The cheapest one dominates them.
That's the core optimization.
This problem teaches an extremely reusable thought process:
What information from the past is actually necessary to make the best decision now?
Instead of storing everything:
7, 1, 5, 3, ...we compress the history into:
minimum price so farThis is a powerful technique.
We scan the array exactly once.
For each price, we perform constant-time operations.
Therefore:
O(n)O(1)This is a huge improvement over brute force:
O(n²) → O(n)while using constant extra space.
Once you understand the logic, you can write:
def maxProfit(prices):
min_price = prices[0]
max_profit = 0
for price in prices[1:]:
max_profit = max(max_profit, price - min_price)
min_price = min(min_price, price)
return max_profitBoth versions are valid.
For interviews, prioritize clarity over cleverness.
Interviewers often test edge cases.
prices = [7, 6, 4, 3, 1]There is no profitable transaction.
Answer:
0prices = [5]You cannot buy and sell on the same day.
Answer:
0prices = [2, 5]Buy at:
2Sell at:
5Profit:
3Answer:
3prices = [5, 5, 5, 5]No profit.
Answer:
0A common incorrect solution is:
minimum = minimum(prices)
maximum = maximum(prices)
profit = maximum - minimumThis is not always correct.
Why?
Because the minimum price must occur before the maximum price.
Consider:
[10, 8, 6, 4, 2]Minimum:
2Maximum:
10Difference:
8But you cannot buy at 2 and sell at 10.
The 2 occurs after 10.
Therefore, the chronological order matters.
The buying price must always come from an earlier day.
That's why the algorithm scans from left to right.
The current state represents:
best buying opportunity so farThis automatically guarantees:
buy → sellin the correct order.
If prices continually decrease:
[9, 7, 5, 3]you shouldn't return:
-6The problem says that if no profitable transaction exists, return:
0That's why:
max_profit = 0is important.
Yes.
You can think of the problem as maintaining the best state at every point.
But implementing a full DP array would be unnecessary.
For this problem, we only need two pieces of information:
minimum price so far
maximum profit so farTherefore, the DP state can be compressed into two variables.
This is an important optimization concept:
If you only need the previous state, you may not need an entire DP table.
This problem is also commonly categorized as a Greedy problem.
At every point, we make a locally useful decision:
Keep the lowest buying price seen so far.
That information is sufficient to calculate the best possible profit if we sell today.
The locally optimal minimum price allows us to discover the globally optimal transaction.
During an interview, watch for phrases such as:
Then ask:
What information from previous elements matters?
Can I maintain that information in a variable?
Can I calculate the answer for the current element using that state?
For this problem:
Previous information:
minimum price
Current information:
today's price
Decision:
today's profit
Answer:
maximum profitThis problem can be reduced to:
Scan Array
↓
Maintain Best Previous Value
↓
Calculate Current Candidate
↓
Update Global AnswerThis pattern is extremely useful.
For example:
minimum so far
maximum so far
best profit so far
best difference so far
best score so farWhenever a problem asks you to compare the current element with something from the past, consider whether a running state can eliminate nested loops.
Once you've solved the basic problem, an interviewer may change the requirements.
What if you can buy and sell multiple times?
This leads to a different problem and a different strategy.
What if every transaction has a fee?
Now the profit calculation changes.
What if after selling, you must wait one day before buying again?
This introduces a more interesting DP state.
Now you need to track multiple transaction states.
This is where the problem becomes significantly more advanced.
Now you enter a broader family of dynamic programming problems.
A simple Easy problem can therefore become a gateway to several Medium and Hard interview problems.
This is what you should take away.
Don't memorize:
min_price = min(min_price, price)Instead, understand:
"I need the cheapest valid buying opportunity before the current selling day."
That sentence naturally leads to:
min_priceThen:
"If I sell today, what profit can I make?"
That leads to:
price - min_priceFinally:
"What's the best profit I've seen?"
That leads to:
max_profitThis is how strong problem solvers approach LeetCode.
Problem:
Maximum profit from one buy + one sell.
Brute Force:
Try every buy/sell combination.
Brute Force:
O(n²) time
O(1) space
Optimized:
One-pass scan.
Maintain:
minimum price so far
maximum profit so far
At every price:
min_price = min(min_price, price)
profit = price - min_price
max_profit = max(max_profit, profit)
Final:
O(n) time
O(1) spaceAfter solving this problem, try variations involving:
k transactions.These problems will gradually introduce Greedy and Dynamic Programming patterns.
LeetCode #121 is not really about stocks.
It is about learning how to replace unnecessary comparisons with a small amount of carefully maintained state.
Instead of:
Compare every pair
↓
O(n²)we do:
Remember the cheapest previous price
↓
Calculate today's possible profit
↓
Keep the best profit
↓
O(n)The most important question to ask yourself in similar problems is:
"What is the minimum information I need to remember from the past to make the best decision now?"
Master that question and you'll start seeing optimization opportunities across many LeetCode problems.
Pixels to Perfection Design that Impresses