二维dp,O(1)转移,1883. 准时抵达会议现场的最小跳过休息次数

一、题目

1、题目描述

给你一个整数 hoursBefore ,表示你要前往会议所剩下的可用小时数。要想成功抵达会议现场,你必须途经 n 条道路。道路的长度用一个长度为 n 的整数数组 dist 表示,其中 dist[i] 表示第 i 条道路的长度(单位:千米)。另给你一个整数 speed ,表示你在道路上前进的速度(单位:千米每小时)。

当你通过第 i 条路之后,就必须休息并等待,直到 下一个整数小时 才能开始继续通过下一条道路。注意:你不需要在通过最后一条道路后休息,因为那时你已经抵达会议现场。

  • 例如,如果你通过一条道路用去 1.4 小时,那你必须停下来等待,到 2 小时才可以继续通过下一条道路。如果通过一条道路恰好用去 2 小时,就无需等待,可以直接继续。

然而,为了能准时到达,你可以选择 跳过 一些路的休息时间,这意味着你不必等待下一个整数小时。注意,这意味着与不跳过任何休息时间相比,你可能在不同时刻到达接下来的道路。

  • 例如,假设通过第 1 条道路用去 1.4 小时,且通过第 2 条道路用去 0.6 小时。跳过第 1 条道路的休息时间意味着你将会在恰好 2 小时完成通过第 2 条道路,且你能够立即开始通过第 3 条道路。

返回准时抵达会议现场所需要的 最小跳过次数 ,如果 无法准时参会 ,返回 -1 。

2、接口描述

python3
class Solution:
    def minSkips(self, dist: List[int], speed: int, hoursBefore: int) -> int:
cpp
class Solution {
public:
    int minSkips(vector<int>& dist, int speed, int hoursBefore) {

    }
};

3、原题链接

1883. 准时抵达会议现场的最小跳过休息次数


二、解题报告

1、思路分析

看到1e3,结合题意,能联想到二维的O(1)状态转移dp或者一维O(n)状态转移线性dp

我们考虑状态设计,每个位置都有跳过rest或不跳过两种选择

定义状态f[i][j]为前i 条路跳过j次的等效行动距离

等效行动距离:假如路径长度为1.5,速度为2,那么不跳过就是要1h,相当于走了2

假如跳过,就是走了1.5

那么有状态转移

f[i][j] = min(f[i - 1][j - 1] + dst[j], f[i - 1][j] + ceil(dst[j] / speed) * speed)

然后发现可以:

滚动数组优化

用整形存储代替浮点数存储进一步优化空间

详细看代码

2、复杂度

时间复杂度:O(n^2) 空间复杂度:O(n)

3、代码详解

python3
class Solution:
    def minSkips(self, dist: List[int], speed: int, hoursBefore: int) -> int:
        n = len(dist)
        f = [[inf] * (n + 1) for _ in range(2)]
        f[0][0] = 0
        for i in range(1, n + 1):
            print("")
            for j in range(i + 1):
                f[i % 2][j] = inf
                if i > j:
                    f[i % 2][j] = min(f[i % 2][j], speed + (f[(i - 1) % 2][j] + dist[i - 1] - 1) // speed * speed)
                if i:
                    f[i % 2][j] = min(f[i % 2][j], f[(i - 1) % 2][j - 1] + dist[i - 1])
        for i in range(n + 1):
            if f[n % 2][i] <= speed * hoursBefore:
                return i
        return -1
cpp
class Solution {
public:
typedef long long LL;
    int minSkips(vector<int>& dist, LL speed, int hoursBefore) {
        int n = dist.size();
        vector<vector<LL>> f(2, vector<LL>(n + 1, 1e18));
        f[0][0]= 0;
        for(int i = 1; i <= n; i++)
            for(int j = 0; j <= i; j++){
                f[i % 2][j] = 1e18;
                if(i > j)
                    f[i % 2][j] = min(f[i % 2][j], speed + (f[(i - 1) % 2][j] + dist[i - 1] - 1) / speed * speed);
                if(j)
                    f[i % 2][j] = min(f[i % 2][j], f[(i - 1) % 2][j - 1] + dist[i - 1]);
            }
        for(int j = 0; j <= n; j++)
            if(f[n % 2][j] <= hoursBefore * speed)
                return j;
        return -1;
    }
};

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EQUINOX1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值