N 辆车沿着一条车道驶向位于 target 英里之外的共同目的地。

每辆车 i 以恒定的速度 speed[i] (英里/小时),从初始位置 position[i] (英里) 沿车道驶向目的地。

一辆车永远不会超过前面的另一辆车,但它可以追上去,并与前车以相同的速度紧接着行驶。

此时,我们会忽略这两辆车之间的距离,也就是说,它们被假定处于相同的位置。

车队 是一些由行驶在相同位置、具有相同速度的车组成的非空集合。注意,一辆车也可以是一个车队。

即便一辆车在目的地才赶上了一个车队,它们仍然会被视作是同一个车队。

会有多少车队到达目的地?

示例:

输入:target = 12, position = [10,8,0,5,3], speed = [2,4,1,1,3]
输出:3
解释:
从 10 和 8 开始的车会组成一个车队,它们在 12 处相遇。
从 0 处开始的车无法追上其它车,所以它自己就是一个车队。
从 5 和 3 开始的车会组成一个车队,它们在 6 处相遇。
请注意,在到达目的地之前没有其它车会遇到这些车队,所以答案是 3。
提示:
0 <= N <= 10 ^ 4
0 < target <= 10 ^ 6
0 < speed[i] <= 10 ^ 6
0 <= position[i] < target
所有车的初始位置各不相同。

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/car-fleet

这道题说是路上有一系列的车,车在不同的位置,且分别有着不同的速度,但行驶的方向都相同。如果后方的车在到达终点之前追上前面的车了,那么它就会如痴汉般尾随在其后,且速度降至和前面的车相同,可以看作是一个车队,当然,单独的一辆车也可以看作是一个车队,问我们共有多少个车队到达终点。这道题是小学时候的应用题的感觉,什么狗追人啊,人追狗啊之类的。这道题的正确解法的思路其实不太容易想,因为我们很容易把注意力都集中到每辆车,去计算其每个时刻所在的位置,以及跟前面的车相遇的位置,这其实把这道题想复杂了,其实并不需要知道车的相遇位置,只关心是否能组成车队一同经过终点线,那么如何才能知道是否能一起过线呢,最简单的方法就是看时间,假如车B在车A的后面,而车B到终点线的时间小于等于车A,那么就知道车A和B一定会组成车队一起过线。这样的话,就可以从离终点最近的一辆车开始,先算出其撞线的时间,然后再一次遍历身后的车,若后面的车撞线的时间小于等于前面的车的时间,则会组成车队。反之,若大于前面的车的时间,则说明无法追上前面的车,于是自己会形成一个新的车队,且是车头,则结果 res 自增1即可。

思路有了,就可以具体实现了,使用一个 TreeMap 来建立小车位置和其到达终点时间之间的映射,这里的时间使用 double 型,通过终点位置减去当前位置,并除以速度来获得。我们希望能从 position 大的小车开始处理,而 TreeMap 是把小的数字排在前面,这里使用了个小 trick,就是映射的时候使用的是 position 的负数,这样就能先处理原来 position 大的车,从而统计出正确的车队数量,参见代码如下:

解法一:

class Solution {
public:
int carFleet(int target, vector<int>& position, vector<int>& speed) {
int res = 0; double cur = 0;
map<int, double> pos2time;
for (int i = 0; i < position.size(); ++i) {
pos2time[-position[i]] = (double)(target - position[i]) / speed[i];
}
for (auto a : pos2time) {
if (a.second <= cur) continue;
cur = a.second;
++res;
}
return res;
}
};

我们也可以使用优先队列来做,由于其是按照从大到小的顺序自动排列的,所以不用使用上面的小 trick。还有一点和上面的不同的是,并没有在开始就计算过线时间,而是直接存的是速度,因为存整型肯定比存 double 型的要节省空间。在之后处理的时候,再取出位置和速度计算时间,然后再进行跟上面相同的操作即可,参见代码如下:

解法二:

class Solution {
public:
int carFleet(int target, vector<int>& position, vector<int>& speed) {
int res = 0; double cur = 0;
priority_queue<pair<int, int>> q;
for (int i = 0; i < position.size(); ++i) {
q.push({position[i], speed[i]});
}
while (!q.empty()) {
auto t = q.top(); q.pop();
double timeNeeded = (double)(target - t.first) / t.second;
if (timeNeeded <= cur) continue;
cur = timeNeeded;
++res;
}
return res;
}
};

方法一:排序

分析

我们首先对这些车辆按照它们的起始位置降序排序,并且用 (target - position) / speed 计算出每辆车在不受其余车的影响时,行驶到终点需要的时间。对于相邻的两辆车 S 和 F,F 的起始位置大于 S,如果 S 行驶到终点需要的时间小于等于 F,那么 S 一定会在终点前追上 F 并形成车队。这是因为在追上 F 之前,S 的行驶速度并不会减小,而 F 却有可能因为追上前面的车辆而速度减小,因此 S 总能在终点前追上 F。

算法

将车辆按照起始位置降序排序后,我们顺序扫描这些车辆。如果相邻的两辆车,前者比后者行驶到终点需要的时间短,那么后者永远追不上前者,即从后者开始的若干辆车辆会组成一个新的车队;如果前者不比后者行驶到终点需要的时间短,那么后者可以在终点前追上前者,并和前者形成车队。此时我们将后者到达终点的时间置为前者到达终点的时间。

Java

class Solution {
public int carFleet(int target, int[] position, int[] speed) {
int N = position.length;
Car[] cars = new Car[N];
for (int i = 0; i < N; ++i)
cars[i] = new Car(position[i], (double) (target - position[i]) / speed[i]);
Arrays.sort(cars, (a, b) -> Integer.compare(a.position, b.position)); int ans = 0, t = N;
while (--t > 0) {
if (cars[t].time < cars[t-1].time) ans++;
else cars[t-1] = cars[t];
} return ans + (t == 0 ? 1 : 0);
}
} class Car {
int position;
double time;
Car(int p, double t) {
position = p;
time = t;
}
}

Python

class Solution(object):
def carFleet(self, target, position, speed):
cars = sorted(zip(position, speed))
times = [float(target - p) / s for p, s in cars]
ans = 0
while len(times) > 1:
lead = times.pop()
if lead < times[-1]: ans += 1
else: times[-1] = lead return ans + bool(times)

复杂度分析

时间复杂度:O(NlogN),即为排序的时间复杂度。

空间复杂度:O(N),存储车辆到达终点需要的时间。

LeetCode——853.车队的更多相关文章

  1. [LeetCode] 853. Car Fleet 车队

    N cars are going to the same destination along a one lane road.  The destination is target miles awa ...

  2. Swift LeetCode 目录 | Catalog

    请点击页面左上角 -> Fork me on Github 或直接访问本项目Github地址:LeetCode Solution by Swift    说明:题目中含有$符号则为付费题目. 如 ...

  3. LeetCode刷题总结-排序、并查集和图篇

    本文介绍LeetCode上有关排序.并查集和图的算法题,推荐刷题总数为15道.具体考点分析如下图: 一.排序 1.数组问题 题号:164. 最大间距,难度困难 题号:324. 摆动排序 II,难度中等 ...

  4. C#LeetCode刷题-栈

    栈篇 # 题名 刷题 通过率 难度 20 有效的括号 C#LeetCode刷题之#20-有效的括号(Valid Parentheses) 33.0% 简单 42 接雨水   35.6% 困难 71 简 ...

  5. [LeetCode] Car Fleet 车队

    N cars are going to the same destination along a one lane road.  The destination is target miles awa ...

  6. 【LeetCode】853. Car Fleet 解题报告(Python)

    [LeetCode]853. Car Fleet 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxu ...

  7. 边工作边刷题:70天一遍leetcode: day 85-3

    Zigzag Iterator 要点: 实际不是zigzag而是纵向访问 这题可以扩展到k个list,也可以扩展到只给iterator而不给list.结构上没什么区别,iterator的hasNext ...

  8. LeetCode.接雨水

    题外话:LeetCode上一个测试用例总是通不过(我在文章末贴出通不过的测试用例),给的原因是超出运行时间,我拿那个测试用例试了下2.037ms运行完.我自己强行给加了这句: && m ...

  9. [Swift]LeetCode853. 车队 | Car Fleet

    N cars are going to the same destination along a one lane road.  The destination is target miles awa ...

随机推荐

  1. libevent简介

    一.参考资料 1.ubuntu下安装libevent 2.libevent实现TCP 服务端

  2. UML-设计模式-本地服务容错-代理模式

    在<本地服务容错-适配器+工厂模式>中,总是优先尝试本地服务.但是,有时候需要先尝试外部服务,然后才是本地服务.GoF的代理模式可以解决这个问题. 1.代理模式的一般结构 2.使用代理模式 ...

  3. SAP_ABAP常用事务代码

    ST05: 性能跟踪(Performance Trace) SE30/SAT: ABAP对象性能分析 ST12: 单个对象性能分析(Single transaction analysis)

  4. Idea的类中使用实体类(有@Data注解)的Get/Set方法报错

    今天从svn上面下了一个maven项目,导入到Idea中之后,发现有的类会使用实体类的Set/Get方法(全报错),导致该问题的原因就是因为实体类中没有这个方法,代码类似如下: @Data publi ...

  5. kill -HUP 什么意思?

    参考 74.在DNS系统测试时,设named进程号是53,命令 D 通知进程重读配置文件.A kill –USR2 53 B kill –USR1 53 C kill -INT 63 D kill – ...

  6. java课程之团队开发冲刺阶段1.8

    一.总结昨天进度 1.实现预装sqlite数据库,将数据库放在app的assets目录下,该目录在打包的时候不会压缩,所以数据库文件可以在安装之后继续使用,然后APP安装之后检测外部存储空间是否有这个 ...

  7. (day 1)创建项目--1

    1.利用cmd(命令行)创建项目myblog 确定好项目要放在哪个directory. dir一下创建好的项目看下有什么 django自带有一个小型的服务器可通过  runserver 启动它 可取浏 ...

  8. MySQL中间件介绍

    360 Atlas Atlas是由 Qihoo 360, Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目.它是在mysql-proxy 0.8.2版本的基础上,对其进行了优化 ...

  9. Vue-router(3)之 router-link 和 router-view 使用

    router 导入 import Vue from 'vue' import Router from 'vue-router' import order from '@/view/New/order. ...

  10. Java学习十八

    学习内容: 1.Java集合 1.自定义的set类添加重复数据需要在实体类中添加hashcode和equals方法. 2.查找set对象信息(以宠物猫为例) //在集合中查找花花的信息并输出 if(s ...