zoukankan      html  css  js  c++  java
  • 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),存储车辆到达终点需要的时间。

  • 相关阅读:
    test from scribefire
    linux下TC+HTB流量控制
    wifi enable
    test
    Android CameraHal CameraAdapter相关(一)
    Android CameraHal 类图分析
    Android CameraHal NativeWindow相关(三)- Leon 5 (mDisplayAdapter->setErrorHandler(mAppCallbackNotifier.get());)
    Android CameraHal NativeWindow相关(二):FrameProvider与NativeWindowDisplayAdapter
    【STM8】添加头文件、加入库函数
    【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(终)-配合内存管理来遍历SD卡
  • 原文地址:https://www.cnblogs.com/wwj99/p/12294068.html
Copyright © 2011-2022 走看看