下课了,牛牛要去食堂吃饭,他们学校的食堂有很多个门,而且整个建筑物是圆形的。只不过要去吃饭的人很多,在里面吃饭的人也很多,所以大家都在门口外面排队等待吃饭。
所以牛牛采取了这样的一个策略:刚开始时,牛牛在第一个门口,如果这个门口有人在排队,那么他选择花费1分钟时间走到下一个门口,如果没有人的话,牛牛就可以直接进去吃饭啦。食堂的每一个门,每1分钟排队的人数都会减少一个。
现在给你门的数量n,和每个门外排队的人的数量,如果按照牛牛的策略,那么牛牛最终会在哪个门进去吃饭呢?请你进行编程求解,返回牛牛最终是从第几个门进入食堂吃饭的。
输入:
4,[2,3,2,0]
返回值:
3
说明:
按照牛牛的策略,每个门口外的排队人数随着时间的变化的结果为[2,3,2,0]→[1,2,1,0]→[0,1,0,0],当牛牛走到第3个门时,刚好没有人排队,所以牛牛最后可以从第3个门进去。
输入:
2,[10,10]
返回值:
1
说明:
按照牛牛的策略,每个门口外的排队人数随着时间的变化的结果为[10,10]→[9,9]→[8,8]→[7,7]→[6,6]→[5,5]→[4,4]→[3,3]→[2,2]→[1,1]→[0,0]
,当牛牛走到第五圈,回到第1个门时,刚好没有人排队,所以牛牛最后可以从第1个门进去。
2≤n≤10^5,代表门的数量
a1?,a2?,...,an?(0≤ai?≤10^9),代表每个门外等待的人数
20%数据,2≤n≤10,0≤ai?≤10
60%数据,2≤n≤10^3,0≤ai?≤10^6
100%数据,2≤n≤10^5,0≤ai?≤10^9
为了解决这个问题,我们可以模拟牛牛的移动过程。牛牛会从第一个门开始,检查每个门是否有人排队,如果有人则等待1分钟并移动到下一个门,否则就直接进入食堂吃饭。为了高效处理这个问题,可以采用一个队列来存储当前需要等待的人数,并通过遍历队列来模拟时间流逝的过程。
以下是一个基于Java的解决方案:
Java
import java.util.*;
public class Solution {
public int nowcoderQueue (int n, int[] a) {
// 创建一个优先队列(默认小顶堆),用于存储门口等待人数和对应的门编号
PriorityQueue<int[]> pq = new PriorityQueue<>((o1, o2) -> o1[0] - o2[0]);
// 将每个门口的等待人数及其门编号放入优先队列
for (int i = 0; i < n; i++) {
if (a[i] > 0) {
pq.offer(new int[]{a[i], i + 1}); // 数组元素从1开始计数
}
}
// 初始化牛牛所在的位置为1(即第一个门)
int position = 1;
int minutes = 0;
// 模拟时间流逝,直到牛牛能够进入某个门为止
while (!pq.isEmpty()) {
// 获取当前等待人数最少的门
int[] currentDoor = pq.poll();
// 如果该门口没有人排队,则牛牛从此门进入食堂
if (currentDoor[0] == 0) {
return currentDoor[1];
} else {
// 否则,减少此门的等待人数,并重新放回队列中
currentDoor[0]--;
pq.offer(currentDoor);
// 牛牛移动到下一个门
position = (position % n) + 1;
// 时间增加1分钟
minutes++;
}
}
// 如果所有门都无人排队,返回1(理论上这种情况不会出现)
return 1;
}
}
这个解决方案首先将每个门口的等待人数及其对应门编号以数组的形式存入优先队列中,然后按照等待人数从小到大进行排序。接着,我们循环模拟时间流逝的过程,每过一分钟,都会检查当前等待人数最少的门,若为空则返回该门编号,否则继续移动到下一门并更新队列中的等待人数。由于题目保证了最终一定能找到无人排队的门,所以无需担心死循环的问题。