Say you have an array for which the i-th element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete at most k transactions.
Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
Example 1:
Input: [2,4,1], k = 2 Output: 2 Explanation: Buy on day 1 (price = 2) and sell on day 2 (price = 4), profit = 4-2 = 2.
Example 2:
Input: [3,2,6,5,0,3], k = 2 Output: 7 Explanation: 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.
The core challenge of this problem is to maximize the profit from at most k transactions. A transaction consists of buying and then selling one share of the stock. The constraint is that you cannot engage in multiple transactions simultaneously, meaning you must sell the stock before you can buy again.
This problem is significant in financial markets where traders aim to maximize their returns by strategically buying and selling stocks. A common pitfall is to assume that more transactions always lead to higher profits, which is not necessarily true due to the constraints.
To solve this problem, we can use dynamic programming. The idea is to maintain a table where the entry at index dp[i][j]
represents the maximum profit achievable using at most i
transactions up to day j
.
We can start with a naive solution that tries all possible pairs of buy and sell days, but this would be inefficient with a time complexity of O(n^2 * k)
. Instead, we can optimize it using dynamic programming to achieve a time complexity of O(n * k)
.
We will use two arrays: dp
and min_price
. The dp
array will store the maximum profit for each transaction up to each day, and the min_price
array will store the minimum price encountered so far for each transaction.
1. Initialize a 2D array dp
with dimensions (k+1) x n
to store the maximum profit for each transaction up to each day.
2. Iterate over the number of transactions from 1 to k
.
3. For each transaction, initialize a variable min_price
to store the minimum price encountered so far.
4. Iterate over the days from 1 to n-1
.
5. Update min_price
to be the minimum of the current min_price
and the difference between the current price and the profit from the previous transaction up to the previous day.
6. Update dp[i][j]
to be the maximum of the previous day's profit and the difference between the current price and min_price
.
7. The answer will be in dp[k][n-1]
.
def maxProfit(k, prices):
# If there are no prices or k is 0, return 0 profit
if not prices or k == 0:
return 0
n = len(prices)
# If k is greater than n//2, it's equivalent to an unlimited number of transactions
if k >= n // 2:
return sum(max(prices[i] - prices[i - 1], 0) for i in range(1, n))
# Initialize the dp array
dp = [[0] * n for _ in range(k + 1)]
# Iterate over the number of transactions
for i in range(1, k + 1):
min_price = prices[0]
for j in range(1, n):
min_price = min(min_price, prices[j] - dp[i - 1][j - 1])
dp[i][j] = max(dp[i][j - 1], prices[j] - min_price)
return dp[k][n - 1]
# Example usage
print(maxProfit(2, [2, 4, 1])) # Output: 2
print(maxProfit(2, [3, 2, 6, 5, 0, 3])) # Output: 7
The time complexity of this solution is O(n * k)
because we have two nested loops iterating over the days and the number of transactions. The space complexity is also O(n * k)
due to the dp
array.
1. If the prices array is empty, the profit should be 0.
2. If k
is 0, the profit should be 0.
3. If k
is greater than or equal to half the number of days, it is equivalent to an unlimited number of transactions.
To test the solution comprehensively, we should include a variety of test cases:
k
is 0 or very large.1. Break down the problem into smaller subproblems and solve them step by step.
2. Use dynamic programming to store intermediate results and avoid redundant calculations.
3. Practice similar problems to improve your problem-solving skills.
In this blog post, we discussed how to solve the "Best Time to Buy and Sell Stock III" problem using dynamic programming. We covered the problem definition, approach, algorithm, code implementation, complexity analysis, edge cases, and testing. Understanding and solving such problems is crucial for improving your algorithmic thinking and coding skills.