题目要求进入考场的学生必须是离别人最远的,那么可以想到用一个最大堆维护区间长度,这样每次插入都只需要在堆头部插入新区间即可。
要注意,当区间的一端不在首尾时,区间长度除以2是新加入的学生距离两边的距离;而区间有一端在首尾时,为了方便计算,令左端点为-1
,右端点为N
,这样,区间长度就等于区间的右端点 - 左端点 - 1
。
在结构体中又加入了哈希表,分别存储座位的左右座位号,方便删除区间,这种做法有点类似链表。
最后在实现的过程中使用了表达式设定堆的排序方式,确保类的封装性,代码如下:
class ExamRoom {
public:
int N;
set<pair<int, int>, std::function<bool(const std::pair<int, int>&, const std::pair<int, int>&)>> interval;
unordered_map<int, int> left;
unordered_map<int, int> right;
ExamRoom(int n) : N(n), interval(compare__())
{
}
std::function<bool(const std::pair<int, int>&, const std::pair<int, int>&)> compare__() const
{
return [this](const std::pair<int, int>& a, const std::pair<int, int>& b)
{
int d1, d2;
if(a.first == -1 || a.second == N)
d1 = a.second - a.first - 1;
else
d1 = (a.second - a.first) / 2;
if(b. first == -1 || b. second == N)
d2 = b.second - b.first - 1;
else
d2 = (b.second - b.first) / 2;
return d1 == d2 ? a.first < b.first : d1 > d2;
};
}
int seat()
{
if(interval.empty())
{
interval.insert({-1, 0});
interval.insert({0, N});
left[0] = -1;
right[-1] = 0;
left[N] = 0;
right[0] = N;
return 0;
}
pair<int, int> tem = *interval.begin();
int p;
if(tem.first == -1)
{
p = 0;
}
else if(tem.second == N)
{
p = N - 1;
}
else
{
p = (tem.first + tem.second) / 2;
}
interval.erase(interval.begin());
interval.insert({tem.first, p});
interval.insert({p, tem.second});
left[p] = tem.first;
right[p] = tem.second;
left[tem.second] = p;
right[tem.first] = p;
return p;
}
void leave(int p)
{
int a = left[p];
int b = right[p];
interval.erase({a, p});
interval.erase({p, b});
interval.insert({a, b});
left.erase(p);
right.erase(p);
right[a] = b;
left[b] = a;
}
};
标签:855,right,tem,int,interval,力扣,second,刷题,first
From: https://www.cnblogs.com/yuhixyui/p/18630805