Best Time to Buy and Sell Stock


Problem Link
Let’s be honest—“Best Time to Buy and Sell Stock” sounds like something you’d Google after watching The Wolf of Wall Street at 2 a.m. and convincing yourself you’re a financial genius. The good news? There’s a greedy algorithm that can help. The bad news? You’ll still need actual money to invest. Sorry.
Problem Statement
You are given an array prices
where prices[i]
is the price of a given stock on the i<sup>th</sup>
day. You want to maximize your profit by choosing a single day to buy one stock and choosing a different day in the future to sell that stock. Return the maximum profit you can achieve from this transaction. If you cannot achieve any profit, return 0
.
Input: prices = [7,1,5,3,6,4]
Output: 5
//Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
//Note that buying on day 2 and selling on day 1 is not allowed because you must buy before you sell.
//Example 2:
Input: prices = [7,6,4,3,1]
Output: 0
//Explanation: In this case, no transactions are done and the max profit = 0.
Before Coding: Think Like a Human
I keep saying this but I cant emphasis its ironic but to be a better coder you have to imagine how to visualise the question understand it, its basically like 2+2 you will be automatically 4 right but when you five years old that was huge you had to think anlayse it and its okay to start a small train your mind till you get there. I’m gonna leave it for you, but feel free to comment on how you think, and remember to understand the question, do a whiteboarding, and write like step by step what you will do to solve it
Problem Understanding (Think Like a Human – The Intuition):
You're watching stock prices day by day. If you bought a stock on any day, when should you sell it to get the most money? What would you do naturally?
Track the lowest price so far (best day to buy).
Every day, check: if I sold today, how much profit would I make based on that lowest price so far?
Keep the highest profit you've ever seen.
Beginner Approach: Brute Force (Nested Loops)
Let’s be real—maybe you’re tired of hearing about brute force solutions. But if that was your first instinct when tackling this problem, hats off to you. Seriously.
When I first saw this question, my mind went straight to brute force too. And honestly? I was so proud just to come up with something that worked and got accepted. That feeling of solving a LeetCode problem, even with a basic approach, is something to be proud of—especially when you’re starting out.
So let’s not downplay it. Brute force is a huge step in understanding the problem. It shows you’ve grasped what’s being asked and figured out a way to make it work. In fact, brute force is how many of us train our minds to recognize patterns and build better solutions later. Think of it as learning the alphabet before writing poetry—you need that foundation.
So if you solved this problem with nested loops and a ton of comparisons, respect. You're building your coding muscle, and you're doing it right. And if you need help, you are in the right spot too, so what’s brute force? It’s the simplest, most direct approach—trying all possible combinations or steps, even if it’s not the most efficient. It’s often your first weapon in your coding toolkit. And that’s perfectly okay.
Let’s walk through it step by step. If we were solving this problem like a human (no code yet), the first thing we’d do is keep track of the best profit we’ve seen so far. In our brain, we’d mentally remember that number—so in code, we do the same by creating a variable. Since this value will change as we find better options, we use let
to declare it: let maxProfit = 0;
. Next, we take the first price and compare it with every other price that comes after it. Sound familiar? Yep—that’s a nested loop! The outer loop starts from index 0, and the inner loop starts from i + 1
, comparing each possible pair of buy and sell days. In our head, we’re subtracting one price from another to see the potential profit. In code, we write: let profit = prices[j] - prices[i];
. Finally, we compare that profit with the max profit we’ve seen so far. If it’s bigger, we update maxProfit
; if not, we just move on. Simple logic, clean steps—easy peasy.
function maxProfit(prices) {
let maxProfit = 0;
for (let i = 0; i < prices.length; i++) {
for (let j = i + 1; j < prices.length; j++) {
let profit = prices[j] - prices[i];
if (profit > maxProfit) {
maxProfit = profit;
}
}
}
return maxProfit;
}
Time Complexity: Due to nested loops, Results in n(n-1)/2* operations = quadratic time O(n²).
Space Complexity: No additional space is used aside from variables like max_profit
and profit
O(1) .
Why not use: As soon as the input size goes beyond a few hundred elements, this approach becomes painfully slow. Plus, you deserve better. There’s literally a one-pass O(n) solution. Why suffer?
That’s it. Nothing fancy. Just human logic translated into code. It’s not the most efficient, but it works—and that’s a huge win when you're learning. Don’t worry about being “inefficient” at first. The key is understanding the why, not just the code. Once you’ve nailed the brute force, then you’re ready to explore smarter, faster solutions like the greedy approach (which we’ll dive into next).
Intermediate Approach: One Pass (Track Min Price)
Let’s take it a step further. This is where you start training your mind to think not just about how to solve the problem, but how to solve it smarter.
Here’s the key mindset shift:
How can I reduce time complexity by avoiding unnecessary comparisons?
That’s it. That’s the question that levels you up.
So what’s unnecessary in brute force? Well, comparing every single pair of days. We don’t need to do that. What we really need is simple:
Track the lowest price we’ve seen so far (because we can only sell after we buy).
At each step, calculate the potential profit if we sold at today’s price.
Update our max profit if that potential profit is better than our best so far.
That’s it. It’s not magic—it’s just observation and logic. Instead of checking every possible pair, we check one thing per loop: “What’s the best I can do today if I had bought at the lowest price before now?”
Here’s the beauty in code:
function maxProfit(prices) {
let minPrice = Infinity;
let maxProfit = 0;
for (let price of prices) {
if (price < minPrice) {
minPrice = price;
} else {
let profit = price - minPrice;
if (profit > maxProfit) {
maxProfit = profit;
}
}
}
return maxProfit;
}
Time Complexity: We’re only going through the list once. O(n).
Space Complexity: No additional space is used aside from variables like max_profit
and profit
O(1) .
Advanced Version: Cleaner Code (Same Logic, Just Sleek)
You're here. You’ve cracked the brute force. You’ve grasped the greedy one-pass approach. Now it’s time to flex your style. Because let’s be honest:
Clean code isn’t just about fewer lines—it’s about clarity, confidence, and control.
We’re still using the same logic:
Track the minimum price.
Calculate profit at each step.
Update the max profit if it improves.
What Changed?
We ditched the
if-else
for built-in functions
Math.min()
andMath.max()
do the heavy lifting, and our code reads like a thought.We start from index 1
Becausemin
is already initialized with the first price—no need to compare it to itself.The logic is still one pass, O(n)
But now it’s more concise, readable, and just... satisfying.
function maxProfit(prices) {
let min = prices[0];
let max = 0;
for (let i = 1; i < prices.length; i++) {
min = Math.min(min, prices[i]);
max = Math.max(max, prices[i] - min);
}
return max;
}
Time Complexity: We’re only going through the list once. O(n).
Space Complexity: No additional space is used aside from variables like max_profit
and profit
O(1) .
What is the Greedy Pattern?
The greedy pattern is an approach to solving problems where you make the best possible choice at each step, hoping that these local choices lead to a globally optimal solution.
“Take the best you can get now, and hope it leads to the best outcome overall.”
Key Characteristics of Greedy Algorithms
Local optimal choice: At each step, pick the option that seems best at that moment.
No backtracking: Once a choice is made, it's final.
Efficient: Often faster than other approaches (like dynamic programming).
Correct only for specific problems: Not all problems can be solved optimally with greedy logic.
Final Thoughts
Another one in the books. If you’ve made it this far, you're not just solving problems. You're building intuition (Before Coding: Think Like a Human). You’ve done the groundwork (Brute Force). You understand the logic (Brute Force). Made it beautiful (Intermediate Solution). Finally, we swap out verbose conditionals with built-in JavaScript functions and structure the loop with clarity and elegance (Advanced Version).
The Big Lesson?
Don’t obsess over clean code too early. First, make it work. Then make it better. Then make it beautiful. Because clean code is not a badge—it’s a habit.
Subscribe to my newsletter
Read articles from Adiam Ahmed directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
