力扣1776.车队Ⅱ - 单调栈维护斜率最值

2023大厂真题提交网址(含题解):

www.CodeFun2000.com(http://101.43.147.120/)

最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练习,体会真题难度。现在OJ已录入50+道2023年最新大厂真题,同时在不断的更新。同时,可以关注"塔子哥学算法"公众号获得每道题的题解。
在这里插入图片描述

题目大意:

一维平面上给你 n n n个汽车在位置 p i p_i pi,以速度 v i v_i vi往右行驶。当两车相遇的时候,速度变为两车最慢速度。现在问你每个车它与下一辆车(车队)相遇的时间。

n ≤ 1 e 5 n \leq 1e5 n1e5

题目思路:

显然我们有一个暴力的 n 2 n^2 n2,对每个车,求出它与后面那些车相遇的最短时间.

画在 s − v s-v sv二维坐标系中,我们就是要求 t = s j − s i v i − v j t=\frac{s_j-s_i}{v_i-v_j} t=vivjsjsi的最小值.那么就是求点对之间的斜率最大值.

分析过程:

这个我们可以利用单调栈来实现:令入栈顺序为: C n , C n − 1 , . . . , C 1 C_n,C_{n-1},...,C_1 Cn,Cn1,...,C1

假设当前点为 C i C_i Ci,栈顶元素 C x C_x Cx

0.若栈为空,则它不会与任何车相遇。

1.若其速度大于等于 C i C_i Ci,则它俩永远不会相遇,则它对 C i C_i Ci的答案的更新没有作用,也对之后的点没有作用。(因为 C i C_i Ci C x , x ∈ [ 1 , i ] C_x,x\in[1,i] Cx,x[1,i]的速度瓶颈,后面的车速度无法超过 C i C_i Ci).所以将其弹出栈顶.

2.1否则,假设栈顶元素和它的最大斜率配对为: ( C x , C y ) , x < y (C_x,C_y),x<y (Cx,Cy),x<y.那么如果 k i , x < k x , y k_{i,x}<k_{x,y} ki,x<kx,y.则 k i , y > k i , x k_{i,y}>k_{i,x} ki,y>ki,x( k k k为点对斜率).这种情况用白话讲就是: C i C_i Ci会在 C x C_x Cx C y C_y Cy相遇之后再汇合。所以对于 C i C_i Ci来讲,瓶颈就是 C y C_y Cy.所以这个时候我们就需要将 C x C_x Cx弹出栈,继续这个过程,如下图所示:
在这里插入图片描述

2.2 反之的话, k i , y < k i , x k_{i,y} < k_{i,x} ki,y<ki,x.这种情况用白话讲就是: C i C_i Ci会在 C x C_x Cx C y C_y Cy相遇之前与 C x C_x Cx汇合。那么答案就是 ( C i , C x ) (C_i,C_x) (Ci,Cx).这个时候停止这个过程即可.如下图所示:

在这里插入图片描述
2.3 结束这个过程后将 i i i入栈.

从上面两个过程可以看出,我们的单调栈就会维护一个下凸包.因为这样是最优的。

class Solution {
public:
    stack<int> s;
    double calc(int i , int j , vector<vector<int>>& a){
        return 1.0 * (a[j][0] - a[i][0]) / (a[i][1] - a[j][1]);
    }
    vector<double> getCollisionTimes(vector<vector<int>>& a) {
        vector<double> ans;
        int n = a.size();
        ans.resize(n);
        ans[n - 1] = -1;
        for (int i = 0 ; i < n ; i++){
            double res = 1e9;
            for (int j = i + 1 ; j < n ; j++){
                if (a[i][1] < a[j][1]) continue;
                res = min (res , calc(i , j , a));
            }
            if (res == 1e9) ans[i] = -1;
            else ans[i] = res;
        }
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值