Taro Logo

Maximum Profit From Trading Stocks

Medium
Amazon logo
Amazon
2 views
Topics:
Dynamic Programming

Trading Stocks for Maximum Profit

You are given a list of daily stock prices, prices, where prices[i] represents the price of a stock on day i. You are also given a list of stocks, where each element in stocks is a list of the form [fixed_cost, profit_multiplier]. You are allowed to make at most k transactions, where each transaction involves buying a single stock on one day and selling it on a later day.

For each transaction, you can choose only one stock to trade. The profit from buying a stock on day buy_day and selling it on day sell_day is calculated as profit_multiplier * (prices[sell_day] - prices[buy_day]) - fixed_cost.

Your goal is to maximize your total profit by making at most k transactions. Note that you can only hold one stock at a time; that is, you must sell a stock before buying another.

Example:

prices = [10, 22, 5, 75, 65, 80] stocks = [[100, 0.1], [10, 1.0]] k = 2

In this example, the prices of a stock over 6 days are given. We can choose from two stocks. For stock 1, the fixed cost is 100 and the profit multiplier is 0.1. For stock 2, the fixed cost is 10 and the profit multiplier is 1.0. We are allowed at most 2 transactions. What is the maximum profit we can make?

Explain your approach, its time and space complexity, and any edge cases you considered.

Solution


Maximum Profit From Trading Stocks

Naive Solution: Brute Force

The most straightforward approach is to try every possible combination of buying and selling stocks within the given constraints. We can iterate through all possible start days and, for each start day, iterate through all possible end days. We can also consider all possible stock choices for each trade.

This involves nested loops and calculating the profit for each combination. However, this approach is highly inefficient due to the exponential nature of the possible combinations.

Example

Let's say we have n days and k stocks. The outer loop iterates n times, the inner loop iterates n times and each trade has k options, which results in potentially O(n^2 * k) combinations to explore for a single trade. If we allow multiple trades, the complexity shoots up dramatically.

Big O Runtime

O(exponential). Due to the overlapping subproblems and redundant calculations.

Big O Space

O(1). No extra space is used.

Optimal Solution: Dynamic Programming

We can use dynamic programming to solve this problem efficiently. We can define dp[i][j] as the maximum profit achievable up to day i with j transactions.

State:

  • i: Represents the day we are currently at (from 0 to n-1).
  • j: Represents the number of transactions we are allowed to make (from 0 to k).

Base Case:

  • dp[0][0] = 0 (No transactions, no profit).
  • dp[i][0] = 0 for all i (No transactions, no profit).
  • dp[0][j] = 0 for all j (No previous days, no profit).

Recurrence Relation:

For each day i and transaction j, we have two options:

  1. Do nothing: dp[i][j] = dp[i-1][j] (The maximum profit remains the same as the previous day).
  2. Make a transaction: Iterate through all previous days m (from 0 to i-1) and find the maximum profit by buying on day m and selling on day i. For the set of stocks stocks: dp[i][j] = max(dp[i][j], dp[m-1][j-1] + profit(m,i,stocks)) where profit(m,i,stocks) is the maximum profit obtained by choosing only one stock to buy on m and sell on i.

Final Answer:

The final answer will be dp[n-1][k], where n is the number of days and k is the maximum number of transactions allowed.

Edge Cases

  • If there are no stocks, return 0.
  • If the number of days is 0 or 1, return 0.
  • If the number of transactions allowed is 0, return 0.
  • If stock prices are decreasing every day, return 0.

Code Implementation (Python)

def maxProfit(prices, stocks, k):
    n = len(prices)
    if not prices or n <= 1 or k == 0 or not stocks:
        return 0

    dp = [[0] * (k + 1) for _ in range(n)]

    for j in range(1, k + 1):
        for i in range(1, n):
            dp[i][j] = dp[i-1][j]
            for m in range(i):
                max_stock_profit = 0
                for stock in stocks:
                    max_stock_profit = max(max_stock_profit, stock[1] * (prices[i] - prices[m]) - stock[0])
                dp[i][j] = max(dp[i][j], dp[m-1][j-1] + max_stock_profit if m > 0 else max_stock_profit)

    return dp[n-1][k]

#Example usage
prices = [10, 22, 5, 75, 65, 80]
stocks = [[100, 0.1], [10, 1.0]]  # [fixed_cost, profit_multiplier]
k = 2

print(maxProfit(prices, stocks, k))

Big O Runtime

O(n^2 * k * s), where n is the number of days, k is the number of transactions, and s is the number of stocks. The triple nested loops dominate the runtime.

Big O Space

O(n * k), where n is the number of days and k is the number of transactions. This is due to the dp table that we use to store intermediate results.