Array · 11 of 36
Best time to buy and Sell stock
Buy a sticker on one day and sell it on a later day, and find the most money you can earn.
- Simple way
- time O(n^2)
room O(1) - Clever way
- time O(n)
room O(1)
The problem, simply
You get a list of prices. prices[i] is the price of one thing on day i. You may buy it once and sell it once, and you must buy before you sell.
Give back the most money you can earn. If prices only go down, you should not trade at all, so the answer is 0.
A story to remember it
Picture it
Six days of prices. The best plan is to buy on day 1 for 1 and sell on day 4 for 6, which earns 5.
- answer
Examples
A normal week
- In
prices = [7, 1, 5, 3, 6, 4]- Out
5
Buy at 1 on day 1, sell at 6 on day 4. Selling on day 0 is not allowed because that is before day 1.
Prices only fall
- In
prices = [7, 6, 4, 3, 1]- Out
0
Every later day is cheaper, so any trade loses money. Do not trade, earn 0.
The cheapest day comes last
- In
prices = [2, 4, 1]- Out
2
The smallest price is 1, but it is on the last day, so you cannot sell after it. The best trade is buy at 2, sell at 4. This is why "biggest minus smallest" is wrong.
One day only
- In
prices = [5]- Out
0
You cannot buy and sell on different days, so the answer is 0.
Way 1: the simple way
Try every pair of days. For each buy day, try every later sell day, and keep the biggest gain.
- Set
best = 0. - For each buy day
i, and each sell dayjafter it, computeprices[j] - prices[i]. - If it is bigger than
best, keep it.
class Solution {
public int maxProfit(int[] prices) {
int best = 0;
for (int i = 0; i < prices.length; i++) { // buy day
for (int j = i + 1; j < prices.length; j++) { // a later sell day
best = Math.max(best, prices[j] - prices[i]);
}
}
return best;
}
}How long it takes: about n * n / 2 pairs of days, so O(n^2). Extra room: two counters, O(1). With a hundred thousand days this is billions of steps, too slow.
Way 2: the clever way
If you sell on day j, the best buy day is the cheapest day before j. So you never need to look back. Walk forward once and carry two numbers:
cheapest: the lowest price seen so far.best: the biggest gain seen so far.
- Start with
cheapestas a huge number andbest = 0. - For each price: first update
cheapestif today is lower. - Then compute
price - cheapest, the gain from selling today, and updatebest.
One walk, remembering the cheapest day
01 / 07
Day 0 costs 7. It is the only day we have seen, so it is the cheapest day so far. Selling on the same day earns 0.
- cheapest
- 7
- sell today
- 0
- best
- 0
- looking now
- checking
- done
- answer
- just added
class Solution {
public int maxProfit(int[] prices) {
int cheapest = Integer.MAX_VALUE; // lowest price seen so far
int best = 0; // most money earned so far
for (int price : prices) {
cheapest = Math.min(cheapest, price); // maybe a new cheapest day
best = Math.max(best, price - cheapest); // sell today?
}
return best;
}
}How long it takes: one walk over the days, O(n). Extra room: two numbers, O(1).
There is a second way to see it. Write down how much the price moves each day: [-6, 4, -2, 3, -2]. Holding the sticker from day i to day j earns the sum of the moves in between. So the answer is the biggest sum of a run of moves, which is exactly Kadane's trick from the maximum subarray problem.
Watch out for
- Start
bestat 0, not at a negative number. Not trading is always allowed. - An empty array or one price must return 0, not crash.
- Update
cheapestbefore computing today's gain, or after. Both work here, because selling on the same day earns 0. Mixing up which price you subtract from which does not work.
What interviewers ask next
- Return the buy and sell days too. Remember the index of
cheapest, and save both days wheneverbestgrows. - Buy and sell as many times as you like. Add up every upward step:
sum of max(0, prices[i] - prices[i-1]). - At most two trades. Keep four numbers: best after first buy, first sell, second buy, second sell, and update them each day.
O(n)time. - At most
ktrades, a waiting day after selling, or a fee per trade. All are small state machines: a few numbers updated each day, one per state. - Why is the greedy walk correct? For each sell day the only buy day that matters is the cheapest earlier one, and we hold exactly that.
Remember this
Grown-up words: the note in your pocket is a running minimum (prefix minimum), the daily moves are price differences, and finding the best run of moves is Kadane's algorithm for maximum subarray sum.