3508 设计路由器

在这里插入图片描述
\qquad这道题对时间复杂度的要求比较高,最多O(logN),考察的点就两个:
\qquad\qquad 1. 数据结构的使用(queue、deque、set、map、tuple)
\qquad\qquad 2. 二分查找

\qquad要求sourcedestinationtimestamp三属性的组合保持唯一、不能重复,可以想到利用Map进行快速查找,但由于三个属性共同组成一个单元,使用哪个作为Key都不能快速定位。转而考虑利用Set进行查找,其存储的元素为三个属性的集合,即tuple<int,int,int>。tuple获取某个位置的元素使用get<n>(tuple),n为元素的位置,从0开始。

\qquad对比一下map与set:

项目MapSetunordered_map
底层结构红黑树红黑树哈希映射表
增删改查复杂度O(log N)O(log N)O(1)
有序性key值升序元素升序无序
唯一性key唯一、value可重复、更改元素唯一,不可更改key唯一、value可重复、更改

队列有两种结构可以选择,队列(queue)和双端队列(deque),可按需选择:
\qquadqueue是仅提供简单的push、pop、front、back接口,不支持迭代器遍历,适用于FIFO的简单任务;
\qquaddeque是升级版,底层为分段数组,支持双端操作、随机访问deque[i]、与迭代器遍历等,适用于需要双端操作的复杂任务。

\qquad题目中为了快速找到同一 destination对应的时间序列,可以通过使用unordered_map<destination, deque<timestamp>>的方式快速找到。

\qquad最后便是二分了,还是要熟悉while写法。要找[startTime, endTime]区间内的的元素个数,可以分别写两个函数找到开头和结尾的元素位置,计算二者间的距离即可。
\qquad二分的通用模版总结,
\qquad\qquadwhile的循环条件为 l < r
\qquad\qquad==的情况与大于或小于合并(由else覆盖)
\qquad\qquad按照if更新一边的值(l/r = mid+1/-1),else内不再更新,直接使用l/r = mid
\qquad\qquad按照不同的更新方式,选择mid上取整/下取整,具体可以考虑r == l+1的情况,根据不同值看是否会陷入死循环来选择取整方式。

\qquad上、下取整的终极实现方式:(看起来麻烦,但是可以防止溢出
\qquad\qquad下取整:l + (r - l) / 2
\qquad\qquad上取整:l + (r - l + 1) / 2

\qquad最后得到的位置还需要检查一下找到的下标是否满足要求。

代码如下:

typedef tuple<int,int,int> T;
typedef deque<int> V;
class Router {
public:
    set<T> packs;
    unordered_map<int,V> m;
    queue<T> que;
    int limit = 0;
    Router(int memoryLimit) {
        limit = memoryLimit;
    }
    
    bool addPacket(int source, int destination, int timestamp) {
        T t1(source, destination, timestamp);
        if(packs.contains(t1)) return false;
        if(que.size() > limit-1)
        {
            T t2 = que.front();
            que.pop();
            m[get<1>(t2)].pop_front();
            packs.erase(t2);
        }
        packs.insert(t1);
        m[destination].push_back(timestamp);
        que.push(t1);
        return true;
    }
    
    vector<int> forwardPacket() {
        vector<int> ans;
        if(que.size() > 0)
        {
            T t1 = que.front();
            ans.push_back(get<0>(t1));
            ans.push_back(get<1>(t1));
            ans.push_back(get<2>(t1));
            que.pop();
            m[get<1>(t1)].pop_front();
            packs.erase(t1);
        }
        return ans;
    }

    int findStart(V& q, int target)
    {
        int l = 0, r = q.size();
        int mid = 0;
        while(l < r)
        {
            mid = l + (r - l)/2;
            if(q[mid] < target) l = mid+1;
            else r = mid;
        }
        return l;
    }

    int findEnd(V& q, int target)
    {
        int l = 0, r = q.size()-1;
        int mid = 0;
        while(l < r)
        {
            mid = l + (r - l + 1) /2;
            if(q[mid] > target) r = mid-1;
            else l = mid;
        }
        return l;
    }
    
    int getCount(int destination, int startTime, int endTime) {
        int ans = 0;
        int start = findStart(m[destination], startTime);
        int end = findEnd(m[destination], endTime);
        if(m[destination][start] >= startTime && m[destination][end] <= endTime) ans = end-start+1;
        return ans;
    }
};

/**
 * Your Router object will be instantiated and called as such:
 * Router* obj = new Router(memoryLimit);
 * bool param_1 = obj->addPacket(source,destination,timestamp);
 * vector<int> param_2 = obj->forwardPacket();
 * int param_3 = obj->getCount(destination,startTime,endTime);
 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值