力扣算法学习day37-2+3-周赛后两道
6010-完成旅途的最少时间
题目
代码实现
class Solution {
public long minimumTime(int[] time, int totalTrips) {
// 二分查找
Arrays.sort(time);
// right为最大时间
long right = 1L * totalTrips * time[0];
long left = 0;
while(left < right){
long mid = (left + right) / 2;
long trips = 0;
for(int i : time){
if(mid < i){
break;
}
trips += mid / i;
}
// 只让left想右移动,trips包含等于totalTrips,保证最后结果是最小的等于totalTrips的数。
if(trips >= totalTrips){
right = mid;
} else{
left = mid + 1;
}
}
return left;
}
}
6011-完成比赛时间的最少时间
题目
class Solution {
public int minimumFinishTime(int[][] tires, int changeTime, int numLaps) {
// 思路看了灵神的思路。具体为什么minSec数组为什么取长度17,可以直接在题解看,主要是灵神直接给的代码
// 还是不是很容易看懂,所以自己做了些注释,方便自己查询和他人也可以看看。
// (1) 按照上面分析,需要先求用一个轮胎跑i圈用时最少多少。用数组minSec[i]表示。
// minSec[i]代表用一个轮胎,跑i圈,所用的最少时间,因为只需要知道最小时间,而不需要知道是哪个轮胎跑的。
// 注:minSec[0]没有用,这样minSec[i]的意义更协调,即用一个轮胎跑i圈用的最少时间。
int[] minSec = new int[18];
// 注:填充数组每个值为Integer.MAX_VALUE / 2 是为了防止(2)中dp的状态转移方程 f[i - j] + minSec[j] 溢出
Arrays.fill(minSec, Integer.MAX_VALUE / 2);
// 枚举每一个轮胎,跑i圈的最小值,然后取跑i圈的最小值。
for (int[] tire : tires) {
int time = tire[0];
// 1.sum大于changeTime + tire[0] 说明换这个轮胎的新轮胎来跑的时间会更短,则
// 可以退出循环了,单个轮胎已经到了能够跑的圈数的极限了。
// 2.i需要小于numLaps是因为题目的圈数是numLaps,那么我们需要求的minSec[i]不需要更大的了。
for (int i = 1, sum = 0; sum <= changeTime + tire[0] && i <= numLaps; i++) {
// 单个轮胎跑i圈的时间迭代。
sum += time;
// 与所有轮胎同i圈 进行比较,取跑i圈时的最小时间。
minSec[i] = Math.min(minSec[i], sum);
// 按照题意,每跑完一圈后,同一个轮胎下一圈消耗的时间会呈指数倍增长.
time *= tire[1];
}
}
// (2) 求得了同一个轮胎跑i圈时的最小时间后,可以求得跑i圈的最短时间。
// 状态传递比较简单,主要注释一下minSec的情况。下面遍历取最小对于出现有单个轮胎跑不到17圈的情况会有影响吗?
// 假设有效的minSec是最多单个跑13圈,那么13圈后都是 Integer.MAX_VALUE / 2,那么先看看条件限制,
// 1 <= fi, changeTime <= 10的5次方,2 <= ri <= 10的5次方,1 <= numLaps <= 1000,所以所用
// 最大时间最大是10的8次方的数量级,远小于Integer.MAX_VALUE / 2,那么在Math.min(dp[i], dp[i - j] + minSec[j])
// 公式中无效的minSec其实就不会取的,一定会被覆盖,所以没有影响。
int[] dp = new int[numLaps + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0;
// dp[i]表示跑i圈,所用的最少时间
for (int i = 1; i <= numLaps; i++) {
// 1.最后j圈由一个轮胎跑,可以得到dp[i] = dp[i - j] + minSec[j],然后j遍历取dp[i]最小。
// 2.每次换轮胎都需要加上changeTime,因为结构原因,所以包括第一个也加上了。
for (int j = 1; j <= Math.min(17, i); j++){
dp[i] = Math.min(dp[i], dp[i - j] + minSec[j]);
}
// 每一圈都
dp[i] += changeTime;
}
// 减去多算了的一次换胎过程(第一次不需要换胎)
return dp[numLaps] - changeTime;
}
}