The problem asks to find the maximum profit achievable by buying and selling stocks, given a budget constraint. We are provided with two arrays, present
and future
, representing the current and future prices of stocks, respectively. We can buy each stock at most once.
The most efficient approach to solve this problem is using dynamic programming. We can model this as a 0/1 knapsack problem, where the "weight" of an item is the current price of a stock and its "value" is the profit from that stock (future price - current price). The knapsack capacity is our budget
.
Both solutions use dynamic programming, but Solution 2 is optimized for space complexity.
Solution 1 (DP with 2D array):
This solution uses a 2D DP table f
where f[i][j]
represents the maximum profit achievable using the first i
stocks and a budget of j
.
The base case is f[0][j] = 0
for all j
, meaning no profit if no stocks are considered.
The recurrence relation is:
f[i][j] = max(f[i-1][j], f[i-1][j - present[i-1]] + future[i-1] - present[i-1])
f[i-1][j]
represents not buying the i
-th stock.f[i-1][j - present[i-1]] + future[i-1] - present[i-1]
represents buying the i
-th stock, if we have enough budget (j >= present[i-1]
) and the profit from that stock is positive (future[i-1] > present[i-1]
).The final answer is f[n][budget]
, where n
is the number of stocks.
Solution 2 (DP with 1D array):
This solution optimizes space complexity by using a 1D DP array f
where f[j]
represents the maximum profit achievable with a budget of j
. It iterates through the stocks and updates the f
array iteratively.
budget
down to a
(the current stock price). This ensures that when considering a stock, we use the previously calculated maximum profit without that stock.f[j] = max(f[j], f[j - a] + b - a)
updates the maximum profit for budget j
considering whether to buy the current stock or not.Solution 1:
budget
is the given budget. This is because we iterate through the DP table.Solution 2:
Solution 1 (2D DP):
class Solution:
def maximumProfit(self, present: List[int], future: List[int], budget: int) -> int:
n = len(present)
f = [[0] * (budget + 1) for _ in range(n + 1)]
for i in range(1, n + 1):
for j in range(budget + 1):
f[i][j] = f[i - 1][j]
if j >= present[i - 1]:
f[i][j] = max(f[i][j], f[i - 1][j - present[i - 1]] + future[i - 1] - present[i - 1])
return f[n][budget]
Solution 2 (1D DP):
class Solution:
def maximumProfit(self, present: List[int], future: List[int], budget: int) -> int:
f = [0] * (budget + 1)
for p, fut in zip(present, future):
for j in range(budget, p - 1, -1):
f[j] = max(f[j], f[j - p] + fut - p)
return f[budget]
Both solutions correctly solve the problem; Solution 2 is preferred due to its better space complexity. The choice between them depends on the specific constraints of the problem (memory limits, etc.).