地铁闸机题

第二题 地铁闸机

某地铁站有一个闸机,同一时刻只允许一名乘客进站或出站,一个乘客通过闸机需要 1 秒钟。

如果在同一时刻,一个乘客要进站,另一个乘客要出站,按如下规则进出站:

l 如果上一秒,闸机没有被使用(即使更早被使用过),那么进站的乘客优先通过;

l 如果上一秒,闸机有乘客进站,那么进站的乘客优先;

l 如果上一秒,闸机有乘客出站,那么出站的乘客优先。

现有一群乘客要通过这个闸机,乘客的到达时刻记录于数组 arrTime 中(升序,可能有重复值),下标表示乘客的编号;乘客的进出站方向记录于direction中(0 表示出站,1 表示进站)。

请按乘客的编号顺序依次返回每个乘客实际通过闸机的时刻。

注意:若多人同时进站,按 arrTime 中下标从小到大顺序通过闸机;若多人同时出站,也按此处理。

Ø 示例 1:

输入:

arrTime = [0,0,1,5]

direction = [0,1,1,0]

输出:[2,0,1,5]

解释:

在 0 时刻,乘客 0(出站)和 1(进站)想要通过闸机。由于闸机上一秒没有被使用,所以乘客 1 优先进站,乘客 0 等待下一时刻;

在 1 时刻,乘客 2(进站)到达闸机,和乘客 0(出站)都要通过闸机。由于上一秒闸机有乘客进站,所以乘客 2 优先进站,乘客 0 继续等待下一时刻;

在 2 时刻,乘客 0 通过闸机;

在 5 时刻,乘客 3 通过闸机。

Ø 示例 2:

输入:

arrTime = [2,2,2,2,3,3,5,5,20,20]

direction = [0,1,1,0,0,1,1,0,0,1]

输出:[6,2,3,7,8,4,5,9,21,20]

解释:

在 2 时刻,乘客 0 和 3 同时出站,乘客 1 和 2 同时进站。由于闸机上一秒没有被使用,进站优先,且下标小的乘客 1 优先通过闸机;

在 20 时刻,乘客 8 要出站,乘客 9 要进站。由于闸机上一秒没有被使用(之前被使用过),所以乘客 9 优先通过闸机。

提示:

l 0 < arrTime.length == direction.length <= 10^5,arrTime[i] 和 direction[i] 分别表示第 i 个乘客的到达时刻和进出站方向

l 0 <= arrTime[i] <= arrTime[i+1] < 10^9

l direction[i] 仅为 0 或 1

答题要求:您编写的代码需要符合 CleanCode 的要求(包括通用编码规范、安全编码规范和圈复杂度)。

这道题看上去没有啥特别的算法,就是直译,条件判断稍麻烦,圈复杂度容易超出。

#include <vector>
#include <queue>
#include <gtest/gtest.h>

using namespace std;

class Solution {
public:
    bool canIn(queue<pair<int, int>> &otherQueue, int machineState, int ticktime,
               pair<int, int> &theOther) const {
        bool shouldPass = false;
        if (machineState == 0 || machineState == 1) {
            shouldPass = true;
        }
        if (machineState == -1) {
            if (otherQueue.size() > 0) {
                theOther = otherQueue.front();
                if (theOther.second > ticktime) {
                    shouldPass = true;
                }
            }
            if (otherQueue.size() == 0) {
                shouldPass = true;
            }
        }
        return shouldPass;
    }

    bool canOut(queue<pair<int, int>> &inQueue, int machineState, int ticktime, const pair<int, int> &currOut,
                pair<int, int> &currIn) const {
        bool shouldPass = false;
        if (currOut.second <= ticktime) {
            if (machineState == 0 || machineState == -1) {
                shouldPass = true;
            }
            if (machineState == 1) {
                if (inQueue.size() > 0) {
                    currIn = inQueue.front();
                    if (currIn.second > ticktime) {
                        shouldPass = true;
                    }
                }
                if (inQueue.size() == 0) {
                    shouldPass = true;
                }
            }
        }
        return shouldPass;
    }

    vector<int> CalcInOutTime(vector<int> arrTimes, vector<int> directions) {
        int size = arrTimes.size();
        vector<int> result(size);
        // 拆分为出站和进站两个队列
        queue<pair<int, int>> inQueue;
        queue<pair<int, int>> outQueue;
        for (int i = 0; i < directions.size(); ++i) {
            if (directions[i] == 1) {
                inQueue.push({i, arrTimes[i]});
            } else {
                outQueue.push({i, arrTimes[i]});
            }
        }

        // 以闸机视角处理
        int machineState = 0; // 上一秒的状态,默认为空闲
        int ticktime = arrTimes[0];
        bool shouldPass = false; // 当前是否可以通过

        pair<int, int> currIn;
        pair<int, int> currOut;

        while (ticktime < arrTimes[size - 1] + size) {
            shouldPass = false;
            // 进一人
            if (inQueue.size() > 0) {
                currIn = inQueue.front();
                if (currIn.second <= ticktime) {
                    shouldPass = canIn(outQueue, machineState, ticktime, currOut);
                }
                if (shouldPass) {
                    result[currIn.first] = ticktime;
                    inQueue.pop();
                    machineState = 1; //进站
                } else {
                    machineState = 0; // 空闲
                }
            }
            // 出一人
            if (!shouldPass && outQueue.size() > 0) {
                currOut = outQueue.front();
                shouldPass = canOut(inQueue, machineState, ticktime, currOut, currIn);

                if (shouldPass) {
                    result[currOut.first] = ticktime;
                    outQueue.pop();
                    machineState = -1; // 出站
                } else {
                    machineState = 0; // 空闲
                }
            }
            // 不过人
            ticktime++;
        }

        return result;
    }
};

测试用例如下:

TEST(SubwayTestSuite, Test1) {
    Solution s;
    vector<int> arrTimes = {2, 2, 2, 2, 3, 3, 5, 5, 20, 20};
    vector<int> directions = {0, 1, 1, 0, 0, 1, 1, 0, 0, 1};

    vector<int> result = s.CalcInOutTime(arrTimes, directions);
    vector<int> expected = {6, 2, 3, 7, 8, 4, 5, 9, 21, 20};
    for (int i = 0; i < expected.size(); ++i) {
        ASSERT_EQ(expected[i], result[i]);
    }
}

TEST(SubwayTestSuite, Test2) {
    Solution s;
    vector<int> arrTimes = {0, 0, 1, 5};
    vector<int> directions = {0, 1, 1, 0};

    vector<int> result = s.CalcInOutTime(arrTimes, directions);
    vector<int> expected = {2, 0, 1, 5};
    for (int i = 0; i < expected.size(); ++i) {
        ASSERT_EQ(expected[i], result[i]);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值