如何调度考生的座位 :: labuladong的算法小抄 #1031
Replies: 12 comments 3 replies
-
这题我用一个堆解决的,由于C++的堆不够灵活,所以直接用vector,借助push_heap、pop_heap再加上自己实现的自定义堆操作,达成双100%,(●'◡'●)。思路就是借助这个堆来维护可用区间,seat和leave都是logN复杂度 |
Beta Was this translation helpful? Give feedback.
-
可以提供一个c++版本么,按照思路写了一个,一直没有跑通。。。 class ExamRoom {
public:
int N; // 记录座位总数量
int distance(const pair<int,int>& a) {
// 返回中点和两个端点最近的距离
int len = (a.second - a.first) / 2;
if(a.first == -1) {
return a.second;
}
if(a.second == N) {
return a.first;
}
return len;
};
struct comp {
bool operator()(pair<int,int>& a, pair<int,int>& b) {
int distA = distance(a);
int distB = distance(b);
// 如果长度相等,那就取index小的
if(distA == distB) {
return a.first < b.first;
}
// 根据线段长度,从大到小排序
return distA > distB;
};
};
set<pair<int, int>, comp> pq; //根据线段长度,从小到大存储所有线段
unordered_map<int, pair<int,int>> startMap; // 以p开头的线段
unordered_map<int, pair<int,int>> endMap; // 以p结尾的线段
// 增加一个线段
void addInterval(const pair<int,int>& p) {
startMap.insert({p.first, p});
endMap.insert({p.second, p});
pq.insert(p);
}
// 删除一个线段
void delInterval(const pair<int,int>& p) {
pq.erase(p);
startMap.erase(p.first);
endMap.erase(p.second);
}
ExamRoom(int n) {
N = n;
// 存放一个虚拟线段[-1, N]
addInterval({-1, N});
}
int seat() {
// 选出最长的线段来
pair<int,int> interval = *pq.begin();
int x = interval.first, y = interval.second;
// 找到线段中点,也就是seat的位置
int seat;
if(x == -1) {
seat = 0;
} else if (y == N) {
seat = N - 1;
} else {
seat = (x + y) / 2;
}
// 删除这个线段, 并插入两个新的线段
delInterval(interval);
addInterval({x, seat});
addInterval({seat, y});
// 返回选择的座位
return seat;
}
void leave(int p) {
// 找到两段的线段
pair<int,int> left = endMap[p];
pair<int,int> right = startMap[p];
// 删除这两个线段,并插入一个新的线段
pair<int,int> newInterval = {left.first, right.second};
delInterval(left);
delInterval(right);
addInterval(newInterval);
}
};
|
Beta Was this translation helpful? Give feedback.
-
困难题细节太多了。。 |
Beta Was this translation helpful? Give feedback.
-
C++版的 class ExamRoom {
private:
set<int>seats;
int maxSeat;
public:
ExamRoom(int n) {
maxSeat=n;
}
int seat() {
if(seats.empty()){
seats.insert(0);
return 0;
}
if(seats.size()==1){
int fir=*(seats.begin());
if(maxSeat-1-fir>fir){
seats.insert(maxSeat-1);
return maxSeat-1;
}else{
seats.insert(0);
return 0;
}
}
int pos=0,now=-1;
int maxdis=-1;
for(auto s:seats){
int dis=(s-now)/2;
if(dis>maxdis){
maxdis=dis;
pos= now==-1 ? 0:now+maxdis;
}
now=s;
}
if(maxdis==0){
seats.insert(maxSeat-1);
return maxSeat-1;
}
else{
seats.insert(pos);
return pos;
}
}
void leave(int p) {
seats.erase(p);
}
}; |
Beta Was this translation helpful? Give feedback.
-
写了一个只用一个TreeSet的版本, Java
|
Beta Was this translation helpful? Give feedback.
-
check in |
Beta Was this translation helpful? Give feedback.
-
@gutouyu 我在你代码上改了一下 可以编译过
|
Beta Was this translation helpful? Give feedback.
-
Python 版本的,自定义带删除功能的堆。直接在heapq上包了一层,更好的办法是参考labuladong堆的实现文章里的方法。 class MyHeap:
def __init__(self):
self.data = []
self.deleted = set()
def top(self):
self.lazy_deletion()
return self.data[0]
def pop(self):
self.lazy_deletion()
return heapq.heappop(self.data)
def delete(self, key):
self.deleted.add(key)
def push(self, key):
if key in self.deleted:
self.deleted.remove(key)
heapq.heappush(self.data, key)
def lazy_deletion(self):
while self.data and self.data[0] in self.deleted:
deletednode = heapq.heappop(self.data)
self.deleted.remove(deletednode)
def is_empty(self):
return self.data is None
class ExamRoom:
def __init__(self, n: int):
self.heap = MyHeap()
self.startMap = dict()
self.endMap = dict()
self.num = 0
self.cap = n
self.insertIntv(0,self.cap-1)
def insertIntv(self,start,end):
#print("insert",start, end)
if start == 0:
self.heap.push((-(end),start, end))
elif end == self.cap - 1:
self.heap.push((-1*((self.cap - 1 - start)),start,end))
else:
self.heap.push(((-1*((end - start)//2), start, end)))
self.startMap[start] = end
self.endMap[end] = start
def delIntv(self, start, end):
#print("delete",start,end)
del self.endMap[end]
del self.startMap[start]
if start == 0:
self.heap.delete((-(end),start, end))
elif end == self.cap - 1:
self.heap.delete((-1*((self.cap - start)),start,end))
else:
self.heap.delete(((-1*((end - start)//2), start, end)))
def seat(self) -> int:
if self.num >= self.cap:
return -1
interval,start,end = self.heap.pop()
if start == 0:
mid = 0
elif end == self.cap - 1 :
mid = self.cap -1
else:
mid = (start + end)//2
self.num += 1
self.delIntv(start,end)
if mid - 1 >= start:
self.insertIntv(start, mid - 1)
if end >= mid + 1:
self.insertIntv(mid + 1, end)
return mid
def leave(self, p: int) -> None:
if p > 0 and p < self.cap - 1:
leftstart = self.endMap.get(p-1,p)
leftend = p - 1 if p - 1 in self.endMap else p
if p -1 in self.endMap:
self.delIntv(leftstart,leftend)
rightend = self.startMap.get(p+1,p)
rightstart = p + 1 if p + 1 in self.startMap else p
if p+1 in self.startMap:
self.delIntv(rightstart, rightend)
self.insertIntv(leftstart,rightend)
if p == 0:
leftend = self.startMap.get(1,p)
leftstart = 1 if 1 in self.startMap else p
if 1 in self.startMap:
self.delIntv(leftstart,leftend)
self.insertIntv(0,leftend)
if p == self.cap - 1:
#print("p=",self.cap - 1,self.endMap)
rightstart = self.endMap.get(p-1,p)
rightend = p - 1 if p - 1 in self.endMap else p
if p - 1 in self.endMap:
self.delIntv(rightstart, rightend)
self.insertIntv(rightstart,p)
self.num -= 1 |
Beta Was this translation helpful? Give feedback.
-
打卡,打卡。依赖数据结构。 对每个边,需要知道左右端点,还需要知道线段的长度。 然后这些边要可以总是取到最大的。这些边还得可以删除。 删除一个学生,需要知道端点对应的边。 |
Beta Was this translation helpful? Give feedback.
-
private int distance(int[] intv) { 有点没明白 既然算的是中点和端点之间的长度, |
Beta Was this translation helpful? Give feedback.
-
seat: leav: 这个为什么两个是反着的? |
Beta Was this translation helpful? Give feedback.
-
public void leave(int p) { |
Beta Was this translation helpful? Give feedback.
-
文章链接点这里:如何调度考生的座位
评论礼仪 见这里,违者直接拉黑。
Beta Was this translation helpful? Give feedback.
All reactions