leetcode 3508 设计路由器 模拟 深拷贝 二分 bound
题目比较复杂,主要体现在流程很长,就是队列加二分的操作
难点1:深拷贝
主要问题1,看下面这段核心代码:
int getCount(int destination, int startTime, int endTime) {
auto times = dest2times[destination];
int ans = 0;
auto lower_it = lower_bound(times.begin(), times.end(), startTime);
size_t lower_idx = lower_it - times.begin();
auto upper_it = upper_bound(times.begin(), times.end(), endTime);
size_t upper_idx = upper_it - times.begin();
ans = upper_idx - lower_idx;
return ans;
}
乍一看是 O ( l o g N ) O(logN) O(logN) 的操作,但实际上,第一步取出来的时候,这一步是深拷贝,就已经花费了 O ( N ) O(N) O(N) 的时间,所以,除了size可以深拷贝,在把较大的数据结构取出来时,一定要注意避免类似的操作。
难点2:二分
上述代码,都减去了times.begin(),其实是重复操作,用下面的代码更为简洁
int getCount(int destination, int startTime, int endTime) {
auto it1 = lower_bound(dest2times[destination].begin(), dest2times[destination].end(), startTime);
auto it2 = upper_bound(dest2times[destination].begin(), dest2times[destination].end(), endTime);
return it2-it1;
}
upper_bound:找到第一个大于目标数的位置
lower_bound:找到第一个大于等于目标数的位置
直接用bound的返回值去减,就可以得到元素数目,若是想得到对应的索引,则需要去减begin()
在非强二分考察题目时,用bound是更为省时、简单的操作。
附ac代码
typedef tuple<int, int, int> T;
typedef deque<int> V;
class Router {
set<T> packets;
map<int, V> dest2times;
queue<T> q;
int limit;
public:
Router(int memoryLimit) {
limit = memoryLimit;
}
bool addPacket(int source, int destination, int timestamp) {
T t1(source, destination, timestamp);
if(packets.count(t1))return false;
if(q.size() == limit){
T t2 = q.front();
dest2times[get<1>(t2)].pop_front();
packets.erase(t2);
q.pop();
}
dest2times[destination].push_back(timestamp);
q.push(t1);
packets.insert(t1);
return true;
}
vector<int> forwardPacket() {
if(q.size() == 0)return vector<int>{};
T t2 = q.front();
dest2times[get<1>(t2)].pop_front();
packets.erase(t2);
q.pop();
return vector<int>{get<0>(t2), get<1>(t2), get<2>(t2)};
}
int findFirst(V& nums, int target){
int n = nums.size();
int l = 0, r = n-1;
while(l<r){
int mid = l + (r-l)/2;
if(nums[mid] < target)l = mid+1;
else r = mid;
}
return l;
}
int findLast(V& nums, int target){
int n = nums.size();
int l = 0, r = n-1;
while(l<r){
int mid = l + (r-l+1)/2;
if(nums[mid] > target)r = mid-1;
else l = mid;
}
return l;
}
int getCount(int destination, int startTime, int endTime) {
int ans = 0;
int start = findFirst(dest2times[destination], startTime);
int end = findLast(dest2times[destination], endTime);
if(dest2times[destination][start] >= startTime and dest2times[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);
*/