Skip to content

983. Minimum Cost For Tickets

On LeetCode ->

Problem

Given sorted travel days and prices for 1-, 7-, and 30-day passes, find the minimum cost to cover every travel day.

Example: days = [1, 4, 6, 7, 8, 20], costs = [2, 7, 15] → 11 (a 1-day pass, a 7-day pass, and another 1-day pass).

Key trick

Let dp[d] be the minimum cost to cover all travel through day d. On a travel day, compare passes ending on that day; on any other day, carry the cost forward.

Trap

A 7-day pass covers its purchase day and the next six days. Also, non-travel days still need DP entries so pass boundaries work correctly.

Why is it interesting?

Buying a longer pass can be optimal even when it starts before the next travel day. The DP avoids having to decide the exact purchase date in advance.

Python solution

class Solution:
    def mincostTickets(self, days: list[int], costs: list[int]) -> int:
        travel = set(days)
        dp = [0] * (days[-1] + 1)

        for d in range(1, len(dp)):
            if d not in travel:
                dp[d] = dp[d - 1]
                continue

            # Each option covers d and looks back past that pass's duration.
            dp[d] = min(
                dp[d - 1] + costs[0],
                dp[max(0, d - 7)] + costs[1],
                dp[max(0, d - 30)] + costs[2],
            )

        return dp[-1]

Time: \(O(D + n)\). Space: \(O(D + n)\), where \(D\) is the last travel day and \(n\) is the number of travel days.

Comment on my solution

Your backward-DP idea is sound: define a state for the next uncovered travel day, then try each pass. The missing step is to compare all three pass choices at each state; making costs the outer loop does not do that naturally.

# Ideas:
# - look like knapsack DP
# - as buying tickets project you forward (to next time you need to buy)
#   - maybe we could run DP backward on days
#   - dp[i] = min cost to travel from day i to the end
# - loop on costs is the outer loop and we go forward
# - I don't see how to solve this


class Solution:
    def mincostTickets(self, days: list[int], costs: list[int]) -> int: