Medium草稿★★★★★O(maxDay) 時間 · O(maxDay) 空間
Dynamic ProgrammingArray
Patterns📈 線性 DP・Kadane
尚未複習過

解法已隱藏 — 先讀題目敘述、自己想想看,再點上方按鈕揭曉。

983Minimum Cost For Tickets1-D DPMedium1-D DP

給定旅行天數陣列 days 和三種票價 costs(1 天、7 天、30 天通行證),求覆蓋所有旅行日的最小花費。

Example:

Input: days = [1,4,6,7,8,20], costs = [2,7,15] Output: 11

Intuition

TIP

以天數為狀態的 DP:每個旅行日選擇買 1/7/30 天票,取最小成本。

Approaches

1. Top-Down Memoization — O(maxDay) / O(maxDay)
  • Idea: 從最後一天往回遞迴,每個旅行日嘗試三種票
  • Time: O(maxDay)
  • Space: O(maxDay)
class Solution {
    fun mincostTickets(days: IntArray, costs: IntArray): Int {
        val daySet = days.toHashSet()
        val lastDay = days.last()
        val memo = IntArray(lastDay + 1) { -1 }
        fun dp(d: Int): Int {
            if (d <= 0) return 0
            if (memo[d] != -1) return memo[d]
            if (d !in daySet) {
                memo[d] = dp(d - 1)
            } else {
                memo[d] = minOf(
                    dp(d - 1) + costs[0],
                    dp(d - 7) + costs[1],
                    dp(d - 30) + costs[2]
                )
            }
            return memo[d]
        }
        return dp(lastDay)
    }
}
⭐ 2. Bottom-Up DP — O(maxDay) / O(maxDay)
  • Idea: 從第 1 天到最後一天逐日計算最小花費
  • Time: O(maxDay)
  • Space: O(maxDay)
class Solution {
    fun mincostTickets(days: IntArray, costs: IntArray): Int {
        val lastDay = days.last()
        val daySet = days.toHashSet()
        val dp = IntArray(lastDay + 1)
        for (i in 1..lastDay) {
            if (i !in daySet) {
                dp[i] = dp[i - 1]
            } else {
                dp[i] = minOf(
                    dp[i - 1] + costs[0],
                    dp[maxOf(0, i - 7)] + costs[1],
                    dp[maxOf(0, i - 30)] + costs[2]
                )
            }
        }
        return dp[lastDay]
    }
}

🔑 Takeaways