Skip to content

Best Time to Buy and Sell Stock ​

Problem Statement ​

You are given an array prices where prices[i] is the price of a given stock on the ith 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.

LeetCode: 121. Best Time to Buy and Sell Stock

Examples ​

Example 1:

text
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:

text
Input: prices = [7,6,4,3,1]
Output: 0
Explanation: In this case, no transactions are done and the max profit = 0.

Constraints ​

  • 1 <= prices.length <= 10^5
  • 0 <= prices[i] <= 10^4

One Pass Approach ​

Best Time to Buy and Sell Stock Visualization

Key Insight ​

Track the minimum price seen so far. At each day, calculate potential profit if we sold today, and update max profit.

Algorithm ​

  1. Initialize min_price to infinity, max_profit to 0
  2. For each price:
    • Update min_price if current price is lower
    • Calculate profit if selling today: price - min_price
    • Update max_profit if this profit is higher
  3. Return max_profit

Solution ​

python
from typing import List

def maxProfit(prices: List[int]) -> int:
    """
    Find maximum profit from single buy and sell.

    Time: O(n) - single pass
    Space: O(1) - constant space
    """
    min_price = float('inf')
    max_profit = 0

    for price in prices:
        if price < min_price:
            min_price = price
        elif price - min_price > max_profit:
            max_profit = price - min_price

    return max_profit
java
import java.util.*;

class Solution {
    public int maxProfit(int[] prices) {
        int minPrice = Integer.MAX_VALUE;
        int maxProfit = 0;

        for (int price : prices) {
            if (price < minPrice) {
                minPrice = price;
            } else if (price - minPrice > maxProfit) {
                maxProfit = price - minPrice;
            }
        }

        return maxProfit;
    }
}

Complexity: Time O(n) · Space O(1)

  • Time: O(n) for single pass through the prices array, tracking minimum and calculating profit at each step
  • Space: O(1) using only constant extra variables regardless of input size
python
# Alternative: More explicit
def maxProfitExplicit(prices: List[int]) -> int:
    """Clearer variable naming."""
    if not prices:
        return 0

    min_price_so_far = prices[0]
    max_profit_so_far = 0

    for price in prices[1:]:
        # Could we have bought cheaper before?
        min_price_so_far = min(min_price_so_far, price)

        # What's the profit if we sell today?
        profit_if_sold_today = price - min_price_so_far

        # Update max profit
        max_profit_so_far = max(max_profit_so_far, profit_if_sold_today)

    return max_profit_so_far


# With buy/sell day tracking
def maxProfitWithDays(prices: List[int]) -> tuple:
    """
    Return (max_profit, buy_day, sell_day).

    Time: O(n)
    Space: O(1)
    """
    if len(prices) < 2:
        return (0, -1, -1)

    min_price = prices[0]
    min_day = 0
    max_profit = 0
    buy_day = -1
    sell_day = -1

    for i in range(1, len(prices)):
        if prices[i] < min_price:
            min_price = prices[i]
            min_day = i
        elif prices[i] - min_price > max_profit:
            max_profit = prices[i] - min_price
            buy_day = min_day
            sell_day = i

    return (max_profit, buy_day, sell_day)

Complexity: Time O(n) · Space O(1)

  • Time: O(n) for single pass through the prices array, tracking minimum and calculating profit at each step
  • Space: O(1) using only constant extra variables regardless of input size

Complexity Analysis ​

ApproachTimeSpace
One PassO(n)O(1)
Brute ForceO(n^2)O(1)

Why This Works ​

The key observation is that we want to find:

  • The minimum price before any given day (potential buy point)
  • The maximum difference between a price and the minimum before it

By tracking min_price as we go, we ensure we're always considering the best possible buy point for any sell day.

Edge Cases ​

  1. Single price: [5] - Cannot make any transaction, return 0
  2. Decreasing prices: [5,4,3,2,1] - No profit possible, return 0
  3. All same prices: [3,3,3,3] - No profit, return 0
  4. Min at end: [5,4,3,2,1,10] - Wait for price at end

Variations ​

Best Time to Buy and Sell Stock II (Multiple Transactions) ​

python
def maxProfitII(prices: List[int]) -> int:
    """
    Multiple transactions allowed (but not simultaneous).
    Greedy: capture all upward movements.

    Time: O(n)
    Space: O(1)
    """
    max_profit = 0

    for i in range(1, len(prices)):
        if prices[i] > prices[i - 1]:
            max_profit += prices[i] - prices[i - 1]

    return max_profit

Best Time to Buy and Sell Stock III (At Most 2 Transactions) ​

python
def maxProfitIII(prices: List[int]) -> int:
    """
    At most 2 transactions.

    Time: O(n)
    Space: O(1)
    """
    buy1 = buy2 = float('inf')
    profit1 = profit2 = 0

    for price in prices:
        # First transaction
        buy1 = min(buy1, price)
        profit1 = max(profit1, price - buy1)

        # Second transaction (buy2 uses profit from first)
        buy2 = min(buy2, price - profit1)
        profit2 = max(profit2, price - buy2)

    return profit2

Best Time to Buy and Sell Stock IV (At Most K Transactions) ​

python
def maxProfitIV(k: int, prices: List[int]) -> int:
    """
    At most k transactions.

    Time: O(n*k)
    Space: O(k)
    """
    if not prices or k == 0:
        return 0

    n = len(prices)

    # If k >= n/2, it's like unlimited transactions
    if k >= n // 2:
        return sum(max(0, prices[i] - prices[i-1])
                   for i in range(1, n))

    # DP approach
    buy = [float('inf')] * (k + 1)
    profit = [0] * (k + 1)

    for price in prices:
        for i in range(1, k + 1):
            buy[i] = min(buy[i], price - profit[i - 1])
            profit[i] = max(profit[i], price - buy[i])

    return profit[k]

With Cooldown ​

python
def maxProfitWithCooldown(prices: List[int]) -> int:
    """
    After selling, must wait one day before buying again.

    Time: O(n)
    Space: O(1)
    """
    if len(prices) < 2:
        return 0

    sold = 0           # Max profit ending with sell
    held = -prices[0]  # Max profit holding stock
    rest = 0           # Max profit in cooldown

    for i in range(1, len(prices)):
        prev_sold = sold
        sold = held + prices[i]
        held = max(held, rest - prices[i])
        rest = max(rest, prev_sold)

    return max(sold, rest)

With Transaction Fee ​

python
def maxProfitWithFee(prices: List[int], fee: int) -> int:
    """
    Each transaction has a fee.

    Time: O(n)
    Space: O(1)
    """
    cash = 0            # Max profit not holding stock
    hold = -prices[0]   # Max profit holding stock

    for i in range(1, len(prices)):
        cash = max(cash, hold + prices[i] - fee)
        hold = max(hold, cash - prices[i])

    return cash
Best Time to Buy and Sell Stock II (LeetCode 122)

Problem: Maximum profit with unlimited transactions.

Key Insight: Collect every upward movement. Buy every valley, sell every peak.

Approach: Sum all positive differences between consecutive days.

Complexity: Time O(n), Space O(1)

Best Time to Buy and Sell Stock III (LeetCode 123)

Problem: Maximum profit with at most 2 transactions.

Key Insight: Track best profit from left and right separately, find optimal split point.

Approach: DP with states: buy1, sell1, buy2, sell2. Or split array approach.

Complexity: Time O(n), Space O(1)

Best Time to Buy and Sell Stock IV (LeetCode 188)

Problem: Maximum profit with at most k transactions.

Key Insight: Generalization of Stock III. DP with k transaction states.

Approach: dp[i][j] = max profit with i transactions on first j days. Use buy/sell states.

Complexity: Time O(nk), Space O(k)

Best Time to Buy and Sell Stock with Cooldown (LeetCode 309)

Problem: Maximum profit with cooldown day after selling.

Key Insight: Three states: hold, sold (cooldown), rest. State machine DP.

Approach: Track max profit in each state. sold -> rest, rest -> hold or rest, hold -> sold or hold.

Complexity: Time O(n), Space O(1)

Best Time to Buy and Sell Stock with Transaction Fee (LeetCode 714)

Problem: Maximum profit with transaction fee on each complete transaction.

Key Insight: Two states: cash (not holding) and hold (holding stock).

Approach: cash = max(cash, hold + price - fee), hold = max(hold, cash - price).

Complexity: Time O(n), Space O(1)