题目地址:https://leetcode.com/problems/minimum-cost-for-tickets/

题目描述

In a country popular for train travel, you have planned some train travelling one year in advance. The days of the year that you will travel is given as an array days. Each day is an integer from 1 to 365.

Train tickets are sold in 3 different ways:

  • a 1-day pass is sold for costs[0] dollars;
  • a 7-day pass is sold for costs[1] dollars;
  • a 30-day pass is sold for costs[2] dollars.

The passes allow that many days of consecutive travel. For example, if we get a 7-day pass on day 2, then we can travel for 7 days: day 2, 3, 4, 5, 6, 7, and 8.

Return the minimum number of dollars you need to travel every day in the given list of days.

Example 1:

  1. Input: days = [1,4,6,7,8,20], costs = [2,7,15]
  2. Output: 11
  3. Explanation:
  4. For example, here is one way to buy passes that lets you travel your travel plan:
  5. On day 1, you bought a 1-day pass for costs[0] = $2, which covered day 1.
  6. On day 3, you bought a 7-day pass for costs[1] = $7, which covered days 3, 4, ..., 9.
  7. On day 20, you bought a 1-day pass for costs[0] = $2, which covered day 20.
  8. In total you spent $11 and covered all the days of your travel.

Example 2:

  1. Input: days = [1,2,3,4,5,6,7,8,9,10,30,31], costs = [2,7,15]
  2. Output: 17
  3. Explanation:
  4. For example, here is one way to buy passes that lets you travel your travel plan:
  5. On day 1, you bought a 30-day pass for costs[2] = $15 which covered days 1, 2, ..., 30.
  6. On day 31, you bought a 1-day pass for costs[0] = $2 which covered day 31.
  7. In total you spent $17 and covered all the days of your travel.

Note:

  1. 1 <= days.length <= 365
  2. 1 <= days[i] <= 365
  3. days is in strictly increasing order.
  4. costs.length == 3
  5. 1 <= costs[i] <= 1000

题目大意

在一年内的某些天会有若干天进行旅行,火车票卖票有三种方式:1天票、7天票、30天票,这几种票的价格分别是costs的三个元素。现在要在这些天内进行旅行,问覆盖这些天最少需要多少钱。

解题方法

动态规划

我竟然没有看出这个题是几个动态规划的题目。

这个题目比较长,但是理解起来还是比较简单的:有三种方式进行选择,要在三种方式里面选择一种,问最少的价格。听起来可以使用搜索的方式进行,应该也是可以的。但是更好的方式就是动态规划。

使用一个 dp 数组,其中 dp[i] 代表着我们旅行到 i 天为止需要的最少旅行价格。那么,如果当前天不需要旅行(不在days中),当然这一天就不用额外买票,所以需要花费的价格等于昨天的价格;如果当前天需要旅行的话,那么需要求三种买票方式的最小价格:昨天的最少价格+一天的票 costs[0],7天前的最少价格+7天的票钱 costs[1] ,30天前的最少价格+30天的票钱 costs[2]。

总之,递推公式是:

  1. dp[i] = dp[i - 1] 当第i天不用旅行
  2. dp[i] = min(dp[i - 1] + costs[0], dp[i - 7] + costs[1], dp[i - 30] + costs[2]) 当第i天需要旅行

实际操作时需要注意向前查找的时候是否越界的问题。

下面的代码里或许不能理解的是为什么把要旅行的天 dp[day] 初始化成0。其实这里真不用考虑太多,这个值只是做了一个标记,代表这天的状态不是INT_MAX,我们在下面计算状态转移的时候会根据这天是不是INT_MAX进行状态转移,等于INT_MAX的代表这天不用旅行,不等INT_MAX的时候代表着需要旅行。所以把days都初始化成一个非INT_MAX的数字即可,我们求需要状态转移的dp[i],需要并且只需要计算三种买票状态的最小值。

C++代码如下:

  1. class Solution {
  2. public:
  3. int mincostTickets(vector<int>& days, vector<int>& costs) {
  4. // dp[i] means min cost for day i
  5. vector<int> dp(366, INT_MAX);
  6. for (int day : days)
  7. dp[day] = 0;
  8. dp[0] = 0;
  9. for (int i = 1; i < 366; ++i) {
  10. if (dp[i] == INT_MAX)
  11. dp[i] = dp[i - 1];
  12. else {
  13. int cur = dp[i - 1] + costs[0];
  14. cur = min(cur, costs[1] + dp[max(0, i - 7)]);
  15. cur = min(cur, costs[2] + dp[max(0, i - 30)]);
  16. dp[i] = cur;
  17. }
  18. }
  19. return dp[days[days.size() - 1]];
  20. }
  21. };

Python代码如下:

  1. class Solution(object):
  2. def mincostTickets(self, days, costs):
  3. """
  4. :type days: List[int]
  5. :type costs: List[int]
  6. :rtype: int
  7. """
  8. dp = [float("inf")] * 366
  9. for day in days:
  10. dp[day] = 0
  11. dp[0] = 0
  12. for i in range(1, 366):
  13. if dp[i] == float("inf"):
  14. dp[i] = dp[i - 1]
  15. else:
  16. cur = dp[i - 1] + costs[0]
  17. cur = min(dp[max(0, i - 7)] + costs[1], cur)
  18. cur = min(dp[max(0, i - 30)] + costs[2], cur)
  19. dp[i] = cur
  20. return dp[days[-1]]

日期

2019 年 1 月 29 日 —— 小年好
2020 年 5 月 6 日 —— 今天的每日一题

【LeetCode】983. 最低票价 Minimum Cost For Tickets(C++ & Python)的更多相关文章

  1. [Swift]LeetCode983. 最低票价 | Minimum Cost For Tickets

    In a country popular for train travel, you have planned some train travelling one year in advance.  ...

  2. 力扣Leetcode 983. 最低票价

    最低票价 在一个火车旅行很受欢迎的国度,你提前一年计划了一些火车旅行.在接下来的一年里,你要旅行的日子将以一个名为 days 的数组给出.每一项是一个从 1 到 365 的整数. 火车票有三种不同的销 ...

  3. Leetcode之动态规划(DP)专题-详解983. 最低票价(Minimum Cost For Tickets)

    Leetcode之动态规划(DP)专题-983. 最低票价(Minimum Cost For Tickets) 在一个火车旅行很受欢迎的国度,你提前一年计划了一些火车旅行.在接下来的一年里,你要旅行的 ...

  4. LeetCode 983. Minimum Cost For Tickets

    原题链接在这里:https://leetcode.com/problems/minimum-cost-for-tickets/ 题目: In a country popular for train t ...

  5. [Swift]LeetCode1000. 合并石头的最低成本 | Minimum Cost to Merge Stones

    There are N piles of stones arranged in a row.  The i-th pile has stones[i] stones. A move consists ...

  6. 【leetcode】983. Minimum Cost For Tickets

    题目如下: In a country popular for train travel, you have planned some train travelling one year in adva ...

  7. LC 983. Minimum Cost For Tickets

    In a country popular for train travel, you have planned some train travelling one year in advance.  ...

  8. 983. Minimum Cost For Tickets

    网址:https://leetcode.com/problems/minimum-cost-for-tickets/ 参考:https://leetcode.com/problems/minimum- ...

  9. [Swift]LeetCode857. 雇佣 K 名工人的最低成本 | Minimum Cost to Hire K Workers

    There are N workers.  The i-th worker has a quality[i] and a minimum wage expectation wage[i]. Now w ...

随机推荐

  1. 【转】NG:垂枝桦基因组图谱构建(2+3组装)及重测序分析

    转自希望组公众号.学习二代+三代组装策略的流程 垂枝桦(Betula pendula)是一种速生乔木,能在短短一年时间内开花,木质坚实,可做细工.家具等,经济价值极高.近日,芬兰研究人员对垂枝桦自交系 ...

  2. python-django使用ORM模型增删改查CRUD

    from weibo.models import WeiboUser as User user_obj = User.objects.get(pk=1) user_obj.pk Out[4]: 1 u ...

  3. mysql order by 多个字段排序实现组内排序

    总结:大组在前,小组在后,计量值再最后,即可实现组内排序:下边是参考别人的具体实例: 工作中需用到order by 后两个字段排序,但结果却产生了一个Bug,以此备录. [1]复现问题场景 为了说明问 ...

  4. Go 性能提升tips--边界检查

    1. 什么是边界检查? 边界检查,英文名 Bounds Check Elimination,简称为 BCE.它是 Go 语言中防止数组.切片越界而导致内存不安全的检查手段.如果检查下标已经越界了,就会 ...

  5. 腾讯云联合中国信通院&作业帮等首发《降本之源-云原生成本管理白皮书》

    在11月4日举办的2021腾讯数字生态大会云原生专场上,腾讯云联合中国信通院.作业帮等率先在国内重磅发布了<降本之源-云原生成本管理白皮书>(简称白皮书),基于腾讯云在业内最大规模的 Ku ...

  6. 内存管理——new delete expression

    C++申请释放内存的方法与详情表 调用情况 1.new expression new表达式在申请内存过程中都发生了什么? 编译器将new这个分解为下面的主要3步代码,①首先调用operator new ...

  7. MySQL学习(一)——创建新用户、数据库、授权

    一.创建用户 1.登录mysql mysql -u root -p 2.创建本地用户>/font> use mysql; //选择mysql数据库 create user 'test'@' ...

  8. mystar01 nodejs MVC 公共CSS,JS设置

    mystar01 nodejs MVC gulp 项目搭建 config/express.js中定义别名 //将下载的第三方库添加到静态资源路径当中,方便访问 app.use('/jquery', e ...

  9. my36_InnoDB关键特性之change buffer

    一.关于IOT:索引组织表 表在存储的时候按照主键排序进行存储,同时在主键上建立一棵树,这样就形成了一个索引组织表,一个表的存储方式以索引的方式来组织存储的. 所以,MySQL表一定要加上主键,通过主 ...

  10. Linux:while read line与for循环的区别

    while read line:是一次性将文件信息读入并赋值给变量line , while中使用重定向机制,文件中的所有信息都被读入并重定向给了整个while 语句中的line 变量. for:是每次 ...