LeetCode——853.车队
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.车队的更多相关文章
- [LeetCode] 853. Car Fleet 车队
N cars are going to the same destination along a one lane road. The destination is target miles awa ...
- Swift LeetCode 目录 | Catalog
请点击页面左上角 -> Fork me on Github 或直接访问本项目Github地址:LeetCode Solution by Swift 说明:题目中含有$符号则为付费题目. 如 ...
- LeetCode刷题总结-排序、并查集和图篇
本文介绍LeetCode上有关排序.并查集和图的算法题,推荐刷题总数为15道.具体考点分析如下图: 一.排序 1.数组问题 题号:164. 最大间距,难度困难 题号:324. 摆动排序 II,难度中等 ...
- C#LeetCode刷题-栈
栈篇 # 题名 刷题 通过率 难度 20 有效的括号 C#LeetCode刷题之#20-有效的括号(Valid Parentheses) 33.0% 简单 42 接雨水 35.6% 困难 71 简 ...
- [LeetCode] Car Fleet 车队
N cars are going to the same destination along a one lane road. The destination is target miles awa ...
- 【LeetCode】853. Car Fleet 解题报告(Python)
[LeetCode]853. Car Fleet 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxu ...
- 边工作边刷题:70天一遍leetcode: day 85-3
Zigzag Iterator 要点: 实际不是zigzag而是纵向访问 这题可以扩展到k个list,也可以扩展到只给iterator而不给list.结构上没什么区别,iterator的hasNext ...
- LeetCode.接雨水
题外话:LeetCode上一个测试用例总是通不过(我在文章末贴出通不过的测试用例),给的原因是超出运行时间,我拿那个测试用例试了下2.037ms运行完.我自己强行给加了这句: && m ...
- [Swift]LeetCode853. 车队 | Car Fleet
N cars are going to the same destination along a one lane road. The destination is target miles awa ...
随机推荐
- HDU 1003:Max Sum
Max Sum Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Su ...
- OpenCV3 Ref SVM : cv::ml::SVM Class Reference
OpenCV3 Ref SVM : cv::ml::SVM Class Reference OpenCV2: #include <opencv2/core/core.hpp>#inclu ...
- 自定义css
/** * 重写FrozenUI */ /** * 按钮 */ body { background-color: #F2F2F2; } @media screen and (-webkit-min-d ...
- 碎碎念(DP)
链接:https://ac.nowcoder.com/acm/contest/3006/F来源:牛客网 题目描述 在ACM比赛里,除了CE以外都是有效的提交.每一个提交都会有其评测的结果,或是AC,或 ...
- LeetCode——39. 组合总和
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的数字可以无限制重复被选 ...
- POJ - 3977 Subset(二分+折半枚举)
题意:有一个N(N <= 35)个数的集合,每个数的绝对值小于等于1015,找一个非空子集,使该子集中所有元素的和的绝对值最小,若有多个,则输出个数最小的那个. 分析: 1.将集合中的元素分成两 ...
- 68.ORM查询条件:date,time,year,week_day等
1. date: 首先查看数据库中article表的信息,由表中的create_time字段可以看出时间为2020.2.5 打印出查询的结果: <QuerySet []>:但是查询的结果为 ...
- 技术沙龙|原来落地AI应用是这么回事儿!
目前人工智能已经迈入应用落地之年,作为备受关注的话题,在重磅政策的加持下市场规模迅速扩大并渗透到各行各业的形势越发鲜明.在此背景下,作为国内不容忽视的创新企业之一,京东AI依托于NeuHub平台对数据 ...
- 使用GitHub+Hexo搭建个人博客
title: CozyMo date: 2019-12-28 16:01:29 tags: 书写 前言:搭建博客要自己打代码吗? 开始动手:搭建博客的步骤 个性化:更换主题!! 写博客:初识 mark ...
- 覆盖(重写)&隐藏
成员函数被重载的特征(1)相同的范围(在同一个类中): (2)函数名字相同: (3)参数不同: (4)virtual 关键字可有可无. 覆盖是指派生类函数覆盖基类函数,特征是(1)不同的范围(分别位于 ...