Best Time to Buy and Sell Stock in Java DSA: From Brute Force to a Single Clean Pass
-
Last Updated: July 28, 2026
-
By: javahandson
-
Series
Solve Best Time to Buy and Sell Stock in Java DSA, from a brute-force pair check to a clean one-pass running-minimum trick, with full step-by-step dry runs.
Best Time to Buy and Sell Stock in Java is one of those problems that looks tricky but hides a very simple idea. You get a list of daily prices. Your job is to buy on one day and sell on a later day for the biggest profit.
There is one rule you cannot break. You must buy before you sell. So you can never sell on a day that comes earlier than your buy day.
If no profit is possible, the answer is just 0. That happens when prices only fall. In that case, it is smarter to not trade at all.
We will solve this in two steps, like we always do. First comes brute force, which checks every buy and sell pair. Then comes a clean one-pass trick that walks the array once and remembers the cheapest day so far.
Every approach gets a full, step-by-step dry run on the same six prices. Nothing is skipped, so you can watch exactly what each line does and what changes at every step.
Let us pin down the rules before we touch any code.
For our array the answer is 5. You buy at 1 on day 1 and sell at 6 on day 4. No other pair beats that gap.
Notice the lowest price, 1, does not sit at the start. And the highest price, 7, sits on day 0 where you cannot use it. That gap between order and value is the whole challenge here.
The profit rule is simple: sell price minus buy price. But the buy day must come first. So a big price early on is useless if nothing cheaper comes before it.
Here is the key trick. As you walk left to right, keep the lowest price you have seen up to now. On each new day, pretend you sell today and buy on that cheapest earlier day.
| 💡 Interview Insight A common opener is “can you do it without nested loops?” Say yes, then explain the one-pass idea: keep the min price so far and check the profit if you sell today. That one line shows you see the trick. |
Try every buy day paired with every later sell day. Keep the biggest profit you find. It is slow, but it proves you understand the goal.
best = 0
for buy from 0 to n-1: // buy day
for sell from buy+1 to n-1: // a later sell day
profit = prices[sell] - prices[buy]
if profit > best:
best = profit
return bestpublic class StockBrute {
public static int maxProfit(int[] prices) {
int best = 0;
for (int buy = 0; buy < prices.length; buy++) {
for (int sell = buy + 1; sell < prices.length; sell++) {
int profit = prices[sell] - prices[buy];
if (profit > best) {
best = profit;
}
}
}
return best;
}
public static void main(String[] args) {
int[] prices = { 7, 1, 5, 3, 6, 4 };
System.out.println(maxProfit(prices)); // 5
}
}Array: [7, 1, 5, 3, 6, 4]. The two loops try every valid buy and sell pair, in order. We trace all 15 of them, so nothing is hidden. Watch the best column climb.
| step | buy (day, price) | sell (day, price) | profit | beats best? | best after |
|---|---|---|---|---|---|
| 1 | 0, 7 | 1, 1 | -6 | No | 0 |
| 2 | 0, 7 | 2, 5 | -2 | No | 0 |
| 3 | 0, 7 | 3, 3 | -4 | No | 0 |
| 4 | 0, 7 | 4, 6 | -1 | No | 0 |
| 5 | 0, 7 | 5, 4 | -3 | No | 0 |
| 6 | 1, 1 | 2, 5 | 4 | Yes | 4 |
| 7 | 1, 1 | 3, 3 | 2 | No | 4 |
| 8 | 1, 1 | 4, 6 | 5 | Yes | 5 |
| 9 | 1, 1 | 5, 4 | 3 | No | 5 |
| 10 | 2, 5 | 3, 3 | -2 | No | 5 |
| 11 | 2, 5 | 4, 6 | 1 | No | 5 |
| 12 | 2, 5 | 5, 4 | -1 | No | 5 |
| 13 | 3, 3 | 4, 6 | 3 | No | 5 |
| 14 | 3, 3 | 5, 4 | 1 | No | 5 |
| 15 | 4, 6 | 5, 4 | -2 | No | 5 |
Let us walk the whole trace, group by group, and see what the loops are doing.
Steps 1 to 5: buy day is 0, price 7.
The outer loop parks the buy on day 0, where the price is 7. That is the most expensive day, so no sell day can turn a profit.
So best stays at 0 through this whole group. Buying at the peak was doomed from the start.
Steps 6 to 9: buy day is 1, price 1.
Now the buy sits on the cheapest day, price 1. This is where the real profits live.
This group found the winning trade at step 8. Buying low at 1 and selling high at 6 gives the top profit of 5.
Steps 10 to 15: buy days 2, 3, then 4.
From here the buy price is never that cheap again, so best cannot grow.
Fifteen pairs were tested in all, yet the answer settled back at step 8. The brute force had to check the other seven pairs anyway, because it has no way to skip them.
Fifteen pairs for six prices is fine. For a few thousand prices it crawls, which is why we improve it next.
Drop the inner loop completely. Walk the prices once, from left to right. Keep the cheapest price seen so far, and on each day check the profit if you sell today. This is the answer interviewers hope to see.
minPrice = a very large number
best = 0
for each price in prices:
todayProfit = price - minPrice
if todayProfit > best:
best = todayProfit
if price < minPrice:
minPrice = price
return bestpublic class StockOnePass {
public static int maxProfit(int[] prices) {
int minPrice = Integer.MAX_VALUE;
int best = 0;
for (int price : prices) {
int todayProfit = price - minPrice;
if (todayProfit > best) {
best = todayProfit;
}
if (price < minPrice) {
minPrice = price;
}
}
return best;
}
public static void main(String[] args) {
int[] prices = { 7, 1, 5, 3, 6, 4 };
System.out.println(maxProfit(prices)); // 5
}
}Array: [7, 1, 5, 3, 6, 4]. We trace every single day. The order matters: we check the profit first, then update minPrice. So minPrice shown is the value used for today’s profit, before any update.
| i (day) | price | minPrice before | todayProfit = price – min | best after | notes |
|---|---|---|---|---|---|
| 0 | 7 | infinity | n/a (min is huge) | 0 | new min = 7 |
| 1 | 1 | 7 | 1 – 7 = -6 | 0 | new min = 1 |
| 2 | 5 | 1 | 5 – 1 = 4 | 4 | best updated |
| 3 | 3 | 1 | 3 – 1 = 2 | 4 | no change |
| 4 | 6 | 1 | 6 – 1 = 5 | 5 | best updated |
| 5 | 4 | 1 | 4 – 1 = 3 | 5 | no change |
Legend: minPrice before is the cheapest price seen on earlier days, used as the buy price for today. todayProfit is what you would earn selling at today’s price. best is the top profit found so far.
Let us go day by day and watch the two values move.
Day 0, price 7.
minPrice still holds its huge starting value, so there is no real buy day yet.
Day 1, price 1.
We first check profit against the current minPrice, which is 7.
Day 2, price 5.
Now minPrice is 1, the best buy day we have found.
Day 3, price 3.
A dip in price does not hurt us. We simply skip it, because selling into a dip earns less.
Day 4, price 6.
This is the winning day, and minPrice is still 1.
Notice how the single stored minimum from day 1 pays off three days later. We never had to look back.
Day 5, price 4.
One pass, two variables, and the answer is 5. The order of the two checks is what makes it correct. We measure today’s profit against an earlier buy first, then lower the minimum, so a price can never buy and sell on the same day.
| 💡 Interview Insight If asked “why check profit before updating minPrice?”, say this: it guarantees the buy day comes strictly before the sell day. Swap the order and a single day could act as both buy and sell, which breaks the rule. |
This is as fast as it gets. You must read every price at least once, and this does exactly that, no more.
Tables are exact, but a sketch often lands faster. Here is the same one-pass trace drawn by hand.

Both give the same answer. They just pay very different prices.
| Approach | How it searches | Time | Space | Note |
|---|---|---|---|---|
| Brute force | Every buy and sell pair | O(n²) | O(1) | Simple, but slow on big inputs |
| One pass | Track cheapest day, sell today | O(n) | O(1) | Fast, lean, the expected answer |
The two share the same tiny memory cost. What splits them is time. The brute force rechecks pairs it could safely skip, while the one pass carries a single minimum and never looks back.
In an interview, start with brute force and name its wasted inner loop. Then tighten it into the one-pass sweep and explain the running minimum. That climb from slow to fast is the story interviewers want to hear.
| 💡 Interview Insight If pushed for the trick in one line, say: “The best sell today always pairs with the cheapest day before it, so I just track that minimum as I go.” That single sentence captures the whole solution. |
A few small traps catch beginners on this problem. Keep them in mind.
Run those falling and single-price cases through your code before you call it done. They catch more bugs than any ordinary input will.
A: It walks the prices array a single time. On each day it reuses one stored value, the cheapest price so far, instead of looping back over earlier days, so the work grows linearly with the number of prices.
A: Zero. No later day beats an earlier buy, so no trade makes money. Starting the best profit at 0 handles this without returning a negative number.
A: It keeps the buy day strictly before the sell day. If you lowered the minimum first, a single day could act as both the buy and the sell, which is not allowed and inflates the profit.
Best Time to Buy and Sell Stock in Java looks like it needs two loops. But once you spot the running-minimum trick, it shrinks to a single clean pass.
Our six-price trace showed the payoff clearly. Brute force ground through all fifteen pairs. The one pass remembered the cheapest day and found the same profit of 5 in a single walk.
So take the pattern, not just the answer. When a problem asks for the best pair in order, ask what you can remember as you go. Often one stored value replaces a whole inner loop.
That habit turns a slow square of work into a quick straight line. It will do the same for many array problems waiting further down the list.
javahandson.com | DSA Series | Arrays & Strings