983. 最低票价
在一个火车旅行很受欢迎的国度,你提前一年计划了一些火车旅行。在接下来的一年里,你要旅行的日子将以一个名为 days
的数组给出。每一项是一个从 1
到 365
的整数。
火车票有 三种不同的销售方式 :
costs[0]
美元;costs[1]
美元;costs[2]
美元。通行证允许数天无限制的旅行。 例如,如果我们在第 2
天获得一张 为期 7 天 的通行证,那么我们可以连着旅行 7 天:第 2
天、第 3
天、第 4
天、第 5
天、第 6
天、第 7
天和第 8
天。
返回 你想要完成在给定的列表 days
中列出的每一天的旅行所需要的最低消费 。
示例 1:
输入:days = [1,4,6,7,8,20], costs = [2,7,15] 输出:11 解释: 例如,这里有一种购买通行证的方法,可以让你完成你的旅行计划: 在第 1 天,你花了 costs[0] = $2 买了一张为期 1 天的通行证,它将在第 1 天生效。 在第 3 天,你花了 costs[1] = $7 买了一张为期 7 天的通行证,它将在第 3, 4, ..., 9 天生效。 在第 20 天,你花了 costs[0] = $2 买了一张为期 1 天的通行证,它将在第 20 天生效。 你总共花了 $11,并完成了你计划的每一天旅行。
示例 2:
输入:days = [1,2,3,4,5,6,7,8,9,10,30,31], costs = [2,7,15] 输出:17 解释: 例如,这里有一种购买通行证的方法,可以让你完成你的旅行计划: 在第 1 天,你花了 costs[2] = $15 买了一张为期 30 天的通行证,它将在第 1, 2, ..., 30 天生效。 在第 31 天,你花了 costs[0] = $2 买了一张为期 1 天的通行证,它将在第 31 天生效。 你总共花了 $17,并完成了你计划的每一天旅行。
提示:
1 <= days.length <= 365
1 <= days[i] <= 365
days
按顺序严格递增costs.length == 3
1 <= costs[i] <= 1000
相似题目
原站题解
cpp 解法, 执行用时: 7 ms, 内存消耗: 13.1 MB, 提交时间: 2024-10-01 08:52:38
class Solution { unordered_set<int> dayset; vector<int> costs; int memo[366] = {0}; public: int mincostTickets(vector<int>& days, vector<int>& costs) { this->costs = costs; for (int d: days) { dayset.insert(d); } memset(memo, -1, sizeof(memo)); return dp(1); } int dp(int i) { if (i > 365) { return 0; } if (memo[i] != -1) { return memo[i]; } if (dayset.count(i)) { memo[i] = min(min(dp(i + 1) + costs[0], dp(i + 7) + costs[1]), dp(i + 30) + costs[2]); } else { memo[i] = dp(i + 1); } return memo[i]; } };
cpp 解法, 执行用时: 3 ms, 内存消耗: 11.6 MB, 提交时间: 2024-10-01 08:52:15
class Solution { private: vector<int> days, costs; vector<int> memo; int durations[3] = {1, 7, 30}; public: int mincostTickets(vector<int>& days, vector<int>& costs) { this->days = days; this->costs = costs; memo.assign(days.size(), -1); return dp(0); } int dp(int i) { if (i >= days.size()) { return 0; } if (memo[i] != -1) { return memo[i]; } memo[i] = INT_MAX; int j = i; for (int k = 0; k < 3; ++k) { while (j < days.size() && days[j] < days[i] + durations[k]) { ++j; } memo[i] = min(memo[i], dp(j) + costs[k]); } return memo[i]; } };
java 解法, 执行用时: 0 ms, 内存消耗: 39.1 MB, 提交时间: 2022-11-28 14:57:50
class Solution { public int mincostTickets(int[] days, int[] costs) { int len = days.length, maxDay = days[len - 1], minDay = days[0]; int[] dp = new int[maxDay + 31]; // 多扩几天,省得判断 365 的限制 // 只需看 maxDay -> minDay,此区间外都不需要出门,不会增加费用 for (int d = maxDay, i = len - 1; d >= minDay; d--) { // i 表示 days 的索引 // 也可提前将所有 days 放入 Set,再通过 set.contains() 判断 if (d == days[i]) { dp[d] = Math.min(dp[d + 1] + costs[0], dp[d + 7] + costs[1]); dp[d] = Math.min(dp[d], dp[d + 30] + costs[2]); i--; // 别忘了递减一天 } else dp[d] = dp[d + 1]; // 不需要出门 } return dp[minDay]; // 从后向前遍历,返回最前的 minDay } }
golang 解法, 执行用时: 8 ms, 内存消耗: 2.6 MB, 提交时间: 2022-11-27 13:23:31
func mincostTickets(days []int, costs []int) int { memo := [366]int{} dayM := map[int]bool{} for _, d := range days { dayM[d] = true } var dp func(day int) int dp = func(day int) int { if day > 365 { return 0 } if memo[day] > 0 { return memo[day] } if dayM[day] { memo[day] = min(min(dp(day + 1) + costs[0], dp(day + 7) + costs[1]), dp(day + 30) + costs[2]) } else { memo[day] = dp(day + 1) } return memo[day] } return dp(1) } func min(x, y int) int { if x < y { return x } return y }
golang 解法, 执行用时: 0 ms, 内存消耗: 2.2 MB, 提交时间: 2022-11-27 13:23:15
func mincostTickets(days []int, costs []int) int { memo := [366]int{} durations := []int{1, 7, 30} var dp func(idx int) int dp = func(idx int) int { if idx >= len(days) { return 0 } if memo[idx] > 0 { return memo[idx] } memo[idx] = math.MaxInt32 j := idx for i := 0; i < 3; i++ { for ; j < len(days) && days[j] < days[idx] + durations[i]; j++ { } memo[idx] = min(memo[idx], dp(j) + costs[i]) } return memo[idx] } return dp(0) } func min(x, y int) int { if x < y { return x } return y }
python3 解法, 执行用时: 68 ms, 内存消耗: 15.6 MB, 提交时间: 2022-11-27 13:22:59
class Solution: def mincostTickets(self, days: List[int], costs: List[int]) -> int: N = len(days) durations = [1, 7, 30] @lru_cache(None) def dp(i): if i >= N: return 0 ans = 10**9 j = i for c, d in zip(costs, durations): while j < N and days[j] < days[i] + d: j += 1 ans = min(ans, dp(j) + c) return ans return dp(0)
python3 解法, 执行用时: 60 ms, 内存消耗: 16.1 MB, 提交时间: 2022-11-27 13:22:39
class Solution: def mincostTickets(self, days: List[int], costs: List[int]) -> int: dayset = set(days) durations = [1, 7, 30] @lru_cache(None) def dp(i): if i > 365: return 0 elif i in dayset: return min(dp(i + d) + c for c, d in zip(costs, durations)) else: return dp(i + 1) return dp(1)