1、心路历程
这道题满足最大最小问题,大概率就是用动态规划。接着,发现当days长度为1时最简单,因此递推方向一定是从n到n-1。假设n-1的问题解决了,那就研究从n-1转移到n有几种不同情况,取动作的最小值即可。
这道题自己写的有点麻烦,但是很朴素;有个技巧是按照天来递推而不是索引,这道题属于灵活转化索引与值的范畴。
2、注意的点:
1、循环的方向不要写反了
2、边界值容易搞混,要分清循环到终止点和循环到头这两种不同情况
解法一:普通动态规划
py
class Solution:
def mincostTickets(self, days: List[int], costs: List[int]) -> int:
@cache
def dp(i): # 前i天的最低消费
# print(i)
if i < 0: return 0
if i == 0: return min(costs[0], costs[1], costs[2]) # 不一定第一天最便宜
res1 = costs[0] + dp(i - 1)
for k1 in range(i-1, -2, -1): # 注意遍历的顺序不要反了,注意处理边界条件
if days[k1] <= days[i] - 7: break
res2 = costs[1] + dp(k1)
for k2 in range(i-1, -2, -1):
if days[k2] <= days[i] - 30: break
res3 = costs[2] + dp(k2)
res = min(res1, res2, res3)
# print(i, res, res1, res2, res3, k1)
return res
return dp(len(days) - 1)
解法二:精简动态规划:
py
class Solution:
def mincostTickets(self, days: List[int], costs: List[int]) -> int:
lastday = days[-1]
@cache
def dp(day_i):
if day_i <= 0: return 0
if day_i not in days: return dp(day_i - 1) # 不在范围内就不花钱
return min(costs[0] + dp(day_i - 1), costs[1] + dp(day_i - 7), costs[2] + dp(day_i - 30))
return dp(lastday)