2188 完成比赛的最少时间(递推)

1. 问题描述:

给你一个下标从 0 开始的二维整数数组 tires ,其中 tires[i] = [fi,ri] 表示第 i 种轮胎如果连续使用,第 x 圈需要耗时 fi * ri(x - 1) 秒。比方说,如果 fi = 3 且 ri = 2 ,且一直使用这种类型的同一条轮胎,那么该轮胎完成第 1 圈赛道耗时 3 秒,完成第 2 圈耗时 3 * 2 = 6 秒,完成第 3 圈耗时 3 * 22 = 12 秒,依次类推。同时给你一个整数 changeTime 和一个整数 numLaps 。比赛总共包含 numLaps 圈,你可以选择任意一种轮胎开始比赛。每一种轮胎都有无数条 。每一圈后,你可以选择耗费 changeTime 秒换成任意一种轮胎(也可以换成当前种类的新轮胎)。请你返回完成比赛需要耗费的最少时间。

示例 1:

输入:tires = [[2,3],[3,4]], changeTime = 5, numLaps = 4
输出:21
解释:
第 1 圈:使用轮胎 0 ,耗时 2 秒。
第 2 圈:继续使用轮胎 0 ,耗时 2 * 3 = 6 秒。
第 3 圈:耗费 5 秒换一条新的轮胎 0 ,然后耗时 2 秒完成这一圈。
第 4 圈:继续使用轮胎 0 ,耗时 2 * 3 = 6 秒。
总耗时 = 2 + 6 + 5 + 2 + 6 = 21 秒。
完成比赛的最少时间为 21 秒。

示例 2:

输入:tires = [[1,10],[2,2],[3,4]],,changeTime = 6, numLaps = 5
输出:25
解释:
第 1 圈:使用轮胎 1 ,耗时 2 秒。
第 2 圈:继续使用轮胎 1 ,耗时 2 * 2 = 4 秒。
第 3 圈:耗时 6 秒换一条新的轮胎 1 ,然后耗时 2 秒完成这一圈。
第 4 圈:继续使用轮胎 1 ,耗时 2 * 2 = 4 秒。
第 5 圈:耗时 6 秒换成轮胎 0 ,然后耗时 1 秒完成这一圈。
总耗时 = 2 + 4 + 6 + 2 + 4 + 6 + 1 = 25 秒。
完成比赛的最少时间为 25 秒。

提示:

1 <= tires.length <= 10 ^ 5
tires[i].length == 2
1 <= fi,changeTime <= 10 ^ 5
2 <= ri <= 10 ^ 5
1 <= numLaps <= 1000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-time-to-finish-the-race/

2. 思路分析:

对于一道困难的题目,一般数据范围为10 ^ 5或者10 ^ 6,所以我们需要将时间复杂度控制在O(n)或者O(nlogn),我们可以考虑能否使用贪心或者dp来解决,直接上感觉可以使用dp来解决,分析题目可以知道存在两种选择,一直使用某种轮胎连续跑x圈或者当跑完x圈之后换其他的轮胎,由于第x圈需要耗费fi * ri ^ (x - 1)的时间,所以连续使用同一种类型的轮胎耗费的时间呈指数级别的增长,所以存在一个上限x使得跑第x圈花费的时间小于等于changeTime  + fi,也即fi * ri ^ (x - 1) <= changeTime + fi,所以需要使得x最大,由于fi,ri越小那么x越大,令fi = 1,ri = 2,那么可以得到:

所以x的上限是18,我们可以先预处理出连续使用某一种类型的轮胎跑x圈的最小耗时将结果存储到min_sec中,我们可以枚举所有的轮胎从而预处理出min_sec值,结合题目的要求(一般看题目要求解的是什么)我们可以定义一个一维数组f,其中f[i]表示跑x圈的最小耗时,由于存在两种策略,连续使用某种类型的轮胎跑x圈或者跑x圈之后换轮胎,所以根据这两种策略进行递推,对于当前的f[i],尝试连续使用某种类型的轮胎跑j圈,可以通过之前预处理的min_sec得到min_sec[j],然后剩余的i - j圈恰好是f[i - j],j最大是min(i,18),最后还需要加上换轮胎的时间就可以得到f[i]的最小值,我们可以将f[0] = -changeTime这样比较方便对状态进行计算,最终的f[numLaps]就是答案,这道题目确实是一道递推的好题,需要好好理解其中状态定义和状态计算的过程。

3. 代码如下:

from cmath import inf
from typing import List


class Solution:
    def minimumFinishTime(self, tires: List[List[int]], changeTime: int, numLaps: int) -> int:
        N = 18
        # 预处理连续使用同一个轮胎跑x圈的最小花费
        min_sec = [inf] * N
        for f, r in tires:
            # count表示当前是第几圈, 下标从1开始
            count = 1
            s, time = 0, f
            while time <= changeTime + f:
                s += time
                min_sec[count] = min(min_sec[count], s)
                time *= r
                count += 1
        # 结合预处理的结果进行递推
        f = [0] * (numLaps + 10)
        # 将f[0]置为-changeTime方便后面的递推
        f[0] = -changeTime
        for i in range(1, numLaps + 1):
            t = inf
            for j in range(1, min(i + 1, N)):
                t = min(t, f[i - j] + min_sec[j])
            f[i] = changeTime + t
        return f[numLaps]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值