|
| 1 | +## Explanation |
| 2 | + |
| 3 | +### Strategy (The "Why") |
| 4 | + |
| 5 | +**Restate the problem:** We are given stock prices for each day and allowed to make at most k transactions. Each transaction can be either a normal transaction (buy then sell) or a short selling transaction (sell then buy back). We must find the maximum profit we can earn. |
| 6 | + |
| 7 | +**1.1 Constraints & Complexity:** |
| 8 | + |
| 9 | +- **Input Size:** We have at most 1000 days (prices.length <= 10^3), and each price is between 1 and 10^9. We can make at most k transactions where k <= prices.length / 2. |
| 10 | +- **Time Complexity:** O(n * k) where n is the number of days and k is the maximum number of transactions. We iterate through each day and for each day, we process all k transactions. |
| 11 | +- **Space Complexity:** O(k) for storing the DP arrays (res, bought, sold) of size k. |
| 12 | +- **Edge Case:** If k is 0, we cannot make any transactions, so the profit is 0. |
| 13 | + |
| 14 | +**1.2 High-level approach:** |
| 15 | + |
| 16 | +The goal is to maximize profit by choosing the best sequence of transactions (normal or short selling) up to k transactions. We use dynamic programming to track the best profit at each stage of transaction completion. |
| 17 | + |
| 18 | +**1.3 Brute force vs. optimized strategy:** |
| 19 | + |
| 20 | +- **Brute Force:** Try all possible combinations of transactions (normal or short) at each day, which would be exponential in complexity O(2^(n*k)). |
| 21 | +- **Optimized Strategy:** Use dynamic programming with three state arrays: `res[j]` tracks best profit after completing j transactions, `bought[j]` tracks best profit when holding a bought position in the j-th transaction, and `sold[j]` tracks best profit when holding a short position in the j-th transaction. This is O(n * k) time and O(k) space. |
| 22 | +- **Optimization:** By maintaining separate states for bought and sold positions, we can efficiently track and update the maximum profit at each stage without recalculating all possibilities. |
| 23 | + |
| 24 | +**1.4 Decomposition:** |
| 25 | + |
| 26 | +1. Initialize three arrays: `res` (completed transactions), `bought` (holding bought positions), and `sold` (holding short positions). |
| 27 | +2. For each day's price, process transactions from k down to 1 (to avoid using updated values). |
| 28 | +3. For each transaction count j, update `res[j]` by completing either a normal transaction (sell) or short transaction (buy back). |
| 29 | +4. Update `bought[j-1]` by starting a new normal transaction (buy at current price). |
| 30 | +5. Update `sold[j-1]` by starting a new short transaction (sell at current price). |
| 31 | +6. Return the maximum value in `res` array. |
| 32 | + |
| 33 | +### Steps (The "How") |
| 34 | + |
| 35 | +**2.1 Initialization & Example Setup:** |
| 36 | + |
| 37 | +Let's use the example input: `prices = [1, 7, 9, 8, 2]`, `k = 2`. |
| 38 | + |
| 39 | +- Initialize `res = [0, 0, 0]` (profit after 0, 1, or 2 completed transactions) |
| 40 | +- Initialize `bought = [-inf, -inf]` (best profit when holding bought position in transaction 0 or 1) |
| 41 | +- Initialize `sold = [0, 0]` (best profit when holding short position in transaction 0 or 1) |
| 42 | + |
| 43 | +**2.2 Start Processing:** |
| 44 | + |
| 45 | +We iterate through each price in the array, updating our DP states. |
| 46 | + |
| 47 | +**2.3 Trace Walkthrough:** |
| 48 | + |
| 49 | +| Day | Price | Transaction | Action | res | bought | sold | |
| 50 | +|-----|-------|-------------|--------|-----|--------|------| |
| 51 | +| 0 | 1 | j=2 | Start normal: bought[1] = max(-inf, res[1] - 1) = max(-inf, 0 - 1) = -1 | [0,0,0] | [-inf,-1] | [0,0] | |
| 52 | +| 0 | 1 | j=1 | Start normal: bought[0] = max(-inf, res[0] - 1) = max(-inf, 0 - 1) = -1 | [0,0,0] | [-1,-1] | [0,0] | |
| 53 | +| 1 | 7 | j=2 | Complete normal: res[2] = max(0, bought[1] + 7) = max(0, -1 + 7) = 6 | [0,0,6] | [-1,-1] | [0,0] | |
| 54 | +| 1 | 7 | j=2 | Start normal: bought[1] = max(-1, res[1] - 7) = max(-1, 0 - 7) = -1 | [0,0,6] | [-1,-1] | [0,0] | |
| 55 | +| 1 | 7 | j=1 | Complete normal: res[1] = max(0, bought[0] + 7) = max(0, -1 + 7) = 6 | [0,6,6] | [-1,-1] | [0,0] | |
| 56 | +| 1 | 7 | j=1 | Start normal: bought[0] = max(-1, res[0] - 7) = max(-1, 0 - 7) = -1 | [0,6,6] | [-1,-1] | [0,0] | |
| 57 | +| 2 | 9 | j=2 | Complete normal: res[2] = max(6, bought[1] + 9) = max(6, -1 + 9) = 8 | [0,6,8] | [-1,-1] | [0,0] | |
| 58 | +| 2 | 9 | j=2 | Start normal: bought[1] = max(-1, res[1] - 9) = max(-1, 6 - 9) = -1 | [0,6,8] | [-1,-1] | [0,0] | |
| 59 | +| 2 | 9 | j=1 | Complete normal: res[1] = max(6, bought[0] + 9) = max(6, -1 + 9) = 8 | [0,8,8] | [-1,-1] | [0,0] | |
| 60 | +| 2 | 9 | j=1 | Start normal: bought[0] = max(-1, res[0] - 9) = max(-1, 0 - 9) = -1 | [0,8,8] | [-1,-1] | [0,0] | |
| 61 | +| 3 | 8 | j=2 | Complete normal: res[2] = max(8, bought[1] + 8) = max(8, -1 + 8) = 8 | [0,8,8] | [-1,-1] | [0,0] | |
| 62 | +| 3 | 8 | j=2 | Start short: sold[1] = max(0, res[1] + 8) = max(0, 8 + 8) = 16 | [0,8,8] | [-1,-1] | [0,16] | |
| 63 | +| 3 | 8 | j=1 | Complete normal: res[1] = max(8, bought[0] + 8) = max(8, -1 + 8) = 8 | [0,8,8] | [-1,-1] | [0,16] | |
| 64 | +| 3 | 8 | j=1 | Start short: sold[0] = max(0, res[0] + 8) = max(0, 0 + 8) = 8 | [0,8,8] | [-1,-1] | [8,16] | |
| 65 | +| 4 | 2 | j=2 | Complete short: res[2] = max(8, sold[1] - 2) = max(8, 16 - 2) = 14 | [0,8,14] | [-1,-1] | [8,16] | |
| 66 | +| 4 | 2 | j=1 | Complete short: res[1] = max(8, sold[0] - 2) = max(8, 8 - 2) = 8 | [0,8,14] | [-1,-1] | [8,16] | |
| 67 | + |
| 68 | +**2.4 Increment and Loop:** |
| 69 | + |
| 70 | +After processing all days, we check all values in the `res` array to find the maximum profit. |
| 71 | + |
| 72 | +**2.5 Return Result:** |
| 73 | + |
| 74 | +The maximum value in `res` is 14, which represents the maximum profit achievable with at most 2 transactions. This comes from: normal transaction (buy at 1, sell at 9) = 8, and short transaction (sell at 8, buy back at 2) = 6, total = 14. |
| 75 | + |
0 commit comments