You are given an integer array prices
where prices[i]
is the price of a given stock on the i
th day, and an integer k
.
Find the maximum profit you can achieve. You may complete at most k
transactions: i.e., you may buy at most k
times and sell at most k
times.
Note: You may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again).
For example:
k = 2
and prices = [2,4,1]
, the output should be 2
. You can buy on day 1 (price = 2) and sell on day 2 (price = 4), with a profit of 4-2 = 2
.k = 2
and prices = [3,2,6,5,0,3]
, the output should be 7
. You can buy on day 2 (price = 2) and sell on day 3 (price = 6), profit = 6-2 = 4
. Then buy on day 5 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3
.Can you provide an efficient algorithm to solve this problem? What is the time and space complexity of your solution? Can you identify and handle any edge cases?
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach to maximizing stock profits with multiple transactions means we'll explore every single possible combination of buying and selling days. We'll consider every way to make up to the allowed number of transactions and then pick the best one.
Here's how the algorithm would work step-by-step:
def max_profit_brute_force(max_transactions, prices):
max_profit = 0
number_of_days = len(prices)
def calculate_profit(transactions):
current_profit = 0
for buy_day, sell_day in transactions:
current_profit += prices[sell_day] - prices[buy_day]
return current_profit
def find_all_combinations(current_transaction_list, start_day, transaction_count):
nonlocal max_profit
# Base case: No more transactions allowed.
if transaction_count == max_transactions:
max_profit = max(max_profit, calculate_profit(current_transaction_list))
return
# This allows for skipping transaction combos
max_profit = max(max_profit, calculate_profit(current_transaction_list))
for buy_day in range(start_day, number_of_days):
for sell_day in range(buy_day + 1, number_of_days):
new_transaction_list = current_transaction_list + [(buy_day, sell_day)]
# Only explore transactions that start after the current one ends.
find_all_combinations(new_transaction_list, sell_day + 1, transaction_count + 1)
# Start the recursion with an empty transaction list
find_all_combinations([], 0, 0)
return max_profit
This problem asks for the most profit achievable with a limited number of stock trades. The clever approach involves making decisions at each price point, tracking our maximum profit after each possible buy or sell. By remembering the best state after each transaction, we avoid exploring every trade combination.
Here's how the algorithm would work step-by-step:
def max_profit_with_k_transactions(max_transactions, stock_prices):
number_of_days = len(stock_prices)
if number_of_days <= 1:
return 0
# For a large number of transactions, use a simpler approach.
if max_transactions >= number_of_days // 2:
max_profit = 0
for day in range(1, number_of_days):
if stock_prices[day] > stock_prices[day - 1]:
max_profit += stock_prices[day] - stock_prices[day - 1]
return max_profit
# Initialize tables to store max profits when holding and not holding stock
dp_holding = [[float('-inf')] * (max_transactions + 1) for _ in range(number_of_days)]
dp_not_holding = [[0] * (max_transactions + 1) for _ in range(number_of_days)]
for transaction in range(1, max_transactions + 1):
dp_holding[0][transaction] = -stock_prices[0]
for day in range(1, number_of_days):
for transaction in range(1, max_transactions + 1):
# Decide whether to buy stock or not
dp_holding[day][transaction] = max(
dp_holding[day - 1][transaction],
dp_not_holding[day - 1][transaction - 1] - stock_prices[day]
)
# Decide whether to sell stock or not
dp_not_holding[day][transaction] = max(
dp_not_holding[day - 1][transaction],
dp_holding[day - 1][transaction] + stock_prices[day]
)
# Return the maximum profit with k transactions
return dp_not_holding[number_of_days - 1][max_transactions]
Case | How to Handle |
---|---|
Empty prices array or k=0 | Return 0 profit immediately as no transactions are possible. |
k is greater than prices.length / 2 | Treat as unlimited transactions and use a simplified greedy approach for efficiency to prevent Time Limit Exceeded (TLE). |
Prices array contains only one element. | Return 0 profit since buying and selling on the same day yields no profit. |
Prices are monotonically increasing (always going up) | The algorithm should maximize profit by buying at the beginning and selling at the end for the allowed number of transactions or perform k single-day transactions. |
Prices are monotonically decreasing (always going down) | Return 0 profit since no profitable transaction can be made. |
Large k value combined with large prices array causing Integer Overflow | Use long data types to prevent integer overflow in calculations of profit. |
Prices array contains duplicate values repeatedly. | The algorithm should handle this and choose the optimal buy/sell points to maximize profit even if prices are the same for multiple days. |
Negative prices or prices containing very large values | The problem statement constraints should explicitly disallow this, but a check should be put in place to validate and return an error or adjust to zero if encountered |