本文主要是介绍2024.4.19力扣每日一题——准时抵达会议现场的最小跳过休息次数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
2024.4.19
- 题目来源
- 我的题解
- 方法一 动态规划+浮点数精度
- 方法二 动态规划+不考虑浮点数精度问题
题目来源
力扣每日一题;题序:1883
我的题解
方法一 动态规划+浮点数精度
参考官方题解。
用 f[i][j]表示经过了 dist[0]到 dist[i−1]的 i 段道路,并且跳过了 j 次的最短用时。
在进行状态转移时,考虑最后一段道路 dist[i−1]是否选择跳过:
- 如果没有跳过,那么状态转移方程为:
f [ i ] [ j ] = ⌈ f [ i − 1 ] [ j ] + dist [ i − 1 ] speed ⌉ f[i][j] = \left\lceil f[i-1][j] + \frac{\textit{dist}[i-1]}{\textit{speed}} \right\rceil f[i][j]=⌈f[i−1][j]+speeddist[i−1]⌉
其中 ⌈x⌉表示将 x向上取整。对于最后一段道路,无需等待到下一个整数小时,但由于题目中给定的 hoursBefore是一个整数,因此在状态转移方程中向上取整是不会影响结果的。- 如果跳过,那么状态转移方程为:
f [ i ] [ j ] = f [ i − 1 ] [ j − 1 ] + dist [ i − 1 ] speed f[i][j] = f[i-1][j-1] + \frac{\textit{dist}[i-1]}{\textit{speed}} f[i][j]=f[i−1][j−1]+speeddist[i−1]由于到达的时间尽可能早,因此需要选择这两种转移中的较小值,即:
f [ i ] [ j ] = min { ⌈ f [ i − 1 ] [ j ] + dist [ i − 1 ] speed ⌉ , f [ i − 1 ] [ j − 1 ] + dist [ i − 1 ] speed } f[i][j] = \min \left\{ \left\lceil f[i-1][j] + \frac{\textit{dist}[i-1]}{\textit{speed}} \right\rceil, f[i-1][j-1] + \frac{\textit{dist}[i-1]}{\textit{speed}}\right\} f[i][j]=min{⌈f[i−1][j]+speeddist[i−1]⌉,f[i−1][j−1]+speeddist[i−1]}
需要注意的是,当 j=0 时,不能通过「跳过」进行转移;当 j=i 时,不能通过「没有跳过」进行转移;当 j>i 时,无法在 i 段道路内跳过超过 i 次,对应的状态不合法。
当计算完所有状态的值后,只需要找到最小的 j,使得 f[n][j]≤hoursBefore,这个 j即为最少需要跳过的次数。如果不存在这样的 jjj,那么返回 −1。
动态规划的细节
- 动态规划的边界条件为 f[0][0]=0,表示初始(未走过任何道路)时的时间为 0。
由于状态转移方程中的取值为 min,因此可以将除了 f[0][0]以外所有的状态置为一个极大值 ∞ \infty ∞,方便进行转移。
浮点数精度问题
引入常量 eps表示一个极小值。在进行「向上取整」运算前,将待取整的浮点数减去 eps再进行取整,就可以避免上述的误差。
同时,需要说明 eps 不会引入其它的问题。在本题中速度最大为 1 0 6 10^6 106,时间与速度成反比,那么 eps 的粒度只需要高于时间的精度 1 0 − 6 10^{-6} 10−6即可,取 1 0 − 7 10^{-7} 10−7 或 1 0 − 8 10^{-8} 10−8 都是可行的。
最后在比较 f[n][j]≤hoursBefore时,也需要将左侧减去 eps或将右侧加上 eps,再进行比较。
时间复杂度:O( n 2 n^2 n2)
空间复杂度:O( n 2 n^2 n2)
public int minSkips(int[] dist, int speed, int hoursBefore) {int n=dist.length;double eps=1e-7;double[][] dp=new double[n+1][n+1];for(int i=0;i<=n;i++){Arrays.fill(dp[i],Double.MAX_VALUE);}dp[0][0]=0;for(int i=1;i<=n;i++){//跳跃次数for(int j=0;j<=i;j++){if(j!=i){dp[i][j]=Math.min(dp[i][j],Math.ceil(dp[i-1][j]+(double)dist[i-1]/speed-eps));}if(j!=0){dp[i][j]=Math.min(dp[i][j],dp[i-1][j-1]+(double)dist[i-1]/speed);}}}for(int i=0;i<=n;i++){if(dp[n][i]<hoursBefore+eps)return i;}return -1;
}
方法二 动态规划+不考虑浮点数精度问题
对所有的除法都乘以speed使其成为整数。将「必须休息并等待,直到下一个整数小时才能开始继续通过下一条道路」,那么当我们将上面的变量都乘以 speed 后,规定应当变更为「必须休息并等待,直到下一个 speed 的倍数小时才能开始继续通过下一条道路」
时间复杂度:O( n 2 n^2 n2)
空间复杂度:O( n 2 n^2 n2)
public int minSkips(int[] dist, int speed, int hoursBefore) {int n=dist.length;long[][] dp=new long[n+1][n+1];for(int i=0;i<=n;i++){Arrays.fill(dp[i],Long.MAX_VALUE);}dp[0][0]=0;for(int i=1;i<=n;i++){//跳跃次数for(int j=0;j<=i;j++){if(j!=i){dp[i][j] = Math.min(dp[i][j], ((dp[i - 1][j] + dist[i - 1] - 1) / speed + 1) * speed);}if(j!=0){dp[i][j]=Math.min(dp[i][j],dp[i-1][j-1]+dist[i-1]);}}}for(int i=0;i<=n;i++){if(dp[n][i]<=(long)hoursBefore*speed)return i;}return -1;
}
有任何问题,欢迎评论区交流,欢迎评论区提供其它解题思路(代码),也可以点个赞支持一下作者哈😄~
这篇关于2024.4.19力扣每日一题——准时抵达会议现场的最小跳过休息次数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!