15.Best Time to Buy and Sell Stock
Problem
You are given an array prices where prices[i] is the price of a stock on day i.
You may complete at most one transaction: choose one day to buy and a later day to sell. Return the maximum profit you can achieve. If no profitable transaction exists, return 0.
Examples
Input: prices = [7, 1, 5, 3, 6, 4]
Output: 5
Explanation: Buy on day 1 (price 1) and sell on day 4 (price 6). Profit = 6 - 1 = 5.
Buying at 1 and selling at 7 is not allowed because day 0 comes before day 1.Input: prices = [7, 6, 4, 3, 1]
Output: 0
Explanation: Prices only fall, so every transaction loses money. Do nothing โ profit 0.Constraints
1 <= prices.length <= 10^50 <= prices[i] <= 10^4
๐ก Key Insight
For any selling day j, the best buying day is simply the cheapest day before j. So we do not need to try every pair โ we sweep left to right, remember the minimum price seen so far, and at each day ask "what if I sold today?". One pass, constant memory.
Brute Force
TimeO(nยฒ)SpaceO(1)Intuition
Try every possible pair (buy day i, sell day j) with i < j and keep the largest prices[j] - prices[i].
Algorithm
- Set
maxProfit = 0. - For each
ifrom0ton - 1: - For each
jfromi + 1ton - 1, updatemaxProfit = max(maxProfit, prices[j] - prices[i]). - Return
maxProfit.
Visualization
prices = [7, 1, 5, 3, 6, 4]
i=0 (7): 1-7, 5-7, 3-7, 6-7, 4-7 โ all negative
i=1 (1): 5-1=4, 3-1=2, 6-1=5 โ, 4-1=3 โ best = 5
i=2 (5): 3-5, 6-5=1, 4-5 โ best stays 5
...
answer = 5Code
class Solution {
public int maxProfit(int[] prices) {
int maxProfit = 0;
for (int i = 0; i < prices.length; i++) {
for (int j = i + 1; j < prices.length; j++) {
// buy on day i, sell on a later day j
maxProfit = Math.max(maxProfit, prices[j] - prices[i]);
}
}
return maxProfit;
}
}Complexity
- Time: O(nยฒ) โ every pair of days is examined; too slow for
n = 10^5. - Space: O(1) โ only a running maximum.
Two Pointers (Sliding Window)
TimeO(n)SpaceO(1)Intuition
Keep a left pointer on the buy day and a right pointer on the sell day. If prices[right] is lower than prices[left], then right is a strictly better buy day for every future sale, so jump left to right. Otherwise, record the profit and keep moving right.
Algorithm
left = 0,maxProfit = 0.- For
rightfrom1ton - 1:- If
prices[right] < prices[left], setleft = right(found a cheaper buy day). - Else update
maxProfit = max(maxProfit, prices[right] - prices[left]).
- If
- Return
maxProfit.
Dry Run
prices = [7, 1, 5, 3, 6, 4]
right=1: 1 < 7 โ left=1
right=2: 5 - 1 = 4 โ max=4
right=3: 3 - 1 = 2 โ max=4
right=4: 6 - 1 = 5 โ max=5
right=5: 4 - 1 = 3 โ max=5Code
class Solution {
public int maxProfit(int[] prices) {
int left = 0; // candidate buy day
int maxProfit = 0;
for (int right = 1; right < prices.length; right++) {
if (prices[right] < prices[left]) {
left = right; // cheaper day found: buy here instead
} else {
maxProfit = Math.max(maxProfit, prices[right] - prices[left]);
}
}
return maxProfit;
}
}Complexity
- Time: O(n) โ
rightvisits each day once. - Space: O(1) โ two indices and a running maximum.
Running MinimumOptimal
TimeO(n)SpaceO(1)Intuition
The same idea expressed more directly: track minPrice, the cheapest price seen so far. Each day, the best profit from selling today is price - minPrice. The answer is the maximum of those values. This is also the cleanest form to extend to related problems (it is Kadane's algorithm on the daily price differences).
Algorithm
minPrice = +infinity,maxProfit = 0.- For each
priceinprices:minPrice = min(minPrice, price).maxProfit = max(maxProfit, price - minPrice).
- Return
maxProfit.
Dry Run
flowchart LR
A["day 0: price 7<br/>min = 7, best = 0"] --> B["day 1: price 1<br/>min = 1, best = 0"]
B --> C["day 2: price 5<br/>min = 1, best = 4"]
C --> D["day 3: price 3<br/>min = 1, best = 4"]
D --> E["day 4: price 6<br/>min = 1, best = 5"]
E --> F["day 5: price 4<br/>min = 1, best = 5"]
F --> G["return 5"]Code
class Solution {
public int maxProfit(int[] prices) {
int minPrice = Integer.MAX_VALUE; // cheapest buy price so far
int maxProfit = 0;
for (int price : prices) {
minPrice = Math.min(minPrice, price);
// profit if we sold today after buying at the cheapest earlier day
maxProfit = Math.max(maxProfit, price - minPrice);
}
return maxProfit;
}
}Complexity
- Time: O(n) โ a single pass over
prices. - Space: O(1) โ two variables.
Complexity Comparison
| Approach | Time | Space |
|---|---|---|
| Brute Force | O(nยฒ) | O(1) |
| Two Pointers | O(n) | O(1) |
| Running Minimum | O(n) | O(1) |
Common Pitfalls
- Taking
max(prices) - min(prices)โ the maximum may occur before the minimum, which would mean selling before buying. - Returning a negative number when prices only fall; the answer must be at least
0(you may skip trading). - Updating
maxProfitbeforeminPriceis fine here, but updatingminPricewith a future value before computing profit is not โ always compare against prices from earlier (or the same) day. - Using a nested loop "because n is small" โ
ngoes up to10^5, so O(nยฒ) times out.