Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Python

หากำไรสูงสุดจากการซื้อขายหุ้นสูงสุด k ครั้งใน Python (DP + Memoization)

ปัญหา: กำหนด Stock Prices `prices[i]` และ Max Transactions `k` หา Max Profit จาก ≤ k Buy-Sell Pairs (ต้อง Buy ก่อน Sell, Sell ก่อน Buy ถัดไป)

อัลกอริทึม: DP Top-Down with Memoization

State: `dp(i, k, holding)` = Max Profit จาก Day i ถึง สิ้นสุด กับ k Transactions เหลือ และ Holding Stock หรือไม่

  • `i`: Current Day Index
  • `k`: Remaining Transactions (แต่ละ Sell = 1 Transaction)
  • `holding`: 0=ไม่ถือหุ้น, 1=ถือหุ้นอยู่

Recurrence


dp(i, k, holding):
    if i == n or k == 0: return 0
    
    if holding:
        # Option 1: Sell Today → Profit + prices[i], k-1, not holding
        # Option 2: Hold → dp(i+1, k, True)
        return max(prices[i] + dp(i+1, k-1, False), dp(i+1, k, True))
    else:
        # Option 1: Buy Today → Profit - prices[i], holding
        # Option 2: Skip → dp(i+1, k, False)
        return max(-prices[i] + dp(i+1, k, True), dp(i+1, k, False))

การติดตั้ง (Top-Down Memoization)


from functools import lru_cache

class Solution:
    def solve(self, prices, k):
        n = len(prices)
        
        @lru_cache(None)
        def dp(i, k, holding):
            if i == n or k == 0:
                return 0
            
            if holding:
                return max(
                    prices[i] + dp(i + 1, k - 1, False),  # Sell
                    dp(i + 1, k, True)                     # Hold
                )
            else:
                return max(
                    -prices[i] + dp(i + 1, k, True),       # Buy
                    dp(i + 1, k, False)                    # Skip
                )
        
        return dp(0, k, False)

# Test
ob = Solution()
prices = [7, 3, 5, 2, 3]
k = 2
print(ob.solve(prices, k))  # 3 (Buy 3 Sell 5, Buy 2 Sell 3)

คำอธิบาย

  • State `(i, k, holding)` Memoized ด้วย `@lru_cache`

  • Base Case: หมดวัน หรือหมด Transactions → Profit 0

  • Holding=True: เลือก Sell (ใช้ 1 Transaction) หรือ Hold

  • Holding=False: เลือก Buy หรือ Skip

  • Start: Day 0, k Transactions, Not Holding

Complexity

  • States: n × k × 2
  • Time: O(n × k)
  • Space: O(n × k) Memoization

Optimization: Bottom-Up DP (O(nk) Time, O(k) Space)


def solve_bottom_up(prices, k):
    n = len(prices)
    if k >= n // 2:  # Unlimited Transactions
        return sum(max(0, prices[i+1] - prices[i]) for i in range(n-1))
    
    # buy[j] = max profit after j-th buy
    # sell[j] = max profit after j-th sell
    buy = [float('-inf')] * (k + 1)
    sell = [0] * (k + 1)
    
    for price in prices:
        for j in range(1, k + 1):
            buy[j] = max(buy[j], sell[j-1] - price)
            sell[j] = max(sell[j], buy[j] + price)
    
    return sell[k]

ตัวอย่าง Trace (prices=[7,3,5,2,3], k=2)


Day 0 (7):  Buy1=-7, Sell1=0, Buy2=-7, Sell2=0
Day 1 (3):  Buy1=-3, Sell1=0, Buy2=-3, Sell2=0
Day 2 (5):  Buy1=-3, Sell1=2, Buy2=-1, Sell2=2
Day 3 (2):  Buy1=-2, Sell1=2, Buy2=0,  Sell2=2
Day 4 (3):  Buy1=-2, Sell1=3, Buy2=0,  Sell2=3  ← Answer

Key Insight: k ≥ n/2 → Unlimited Transactions Problem (Greedy: Sum All Positive Diffs)