题目链接
分析:题目意思是要我们将一个数组 people[i] = {h,k},放到一个位置,并且能保证,这个位置前面有k个h大于等于当前h的。
首先说一下需要使用到的变量:
res[][]:用来记录最终答案的二维数组
vis[]:用来记录这个位置是否已经放置了元素
count:用来记录前面有几个大于等于当前h的元素
那么我们可以反过来想,首先找到一个最小的h,那么其它的h肯定比当前大,那么只需要考虑前面有k个位置就行,也就是说,当前这个放到第k+1个位置就行。(这里为了简单,先没考虑有相同的h)
下面我们再考虑有相同h的情况。
其实也很好考虑。
我们从res的第0个开始遍历,当count还小于k的时候,那么说明还要继续往后遍历,因为还没找到合适的位置。
那么什么时候count自增呢,也就是说,什么时候才叫找到了一个大于等于当前h的位置呢?
第一:遍历到当前位置没有被访问,因为每次我们都需要拿出people中剩下的最小的,所以,还没有被访问的肯定是放后面元素的,所以肯定是大于等于当前h的,此时count+1.
第二:遍历到元素等于当前h,也就是有相同h存在的情况,此时也是count+1。
直到People都放到了res即可。
那么此时还有两个问题
问题一:就是我们每次怎么去找h最小的?
问题二:并且如果当前剩下的people中最小的h有多个,应该选择哪一个?
问题一:
我们可以将people放到小顶堆中,这样每次拿到的就是h最小的。
问题二:
如果h相同,那么我们应该选择k最小的,因为h相同,k最小的肯定放在前面。
代码:
class Solution {
public int[][] reconstructQueue(int[][] people) {
//小顶堆 h小的放上面, h相同则k小的放上面
Queue<int[]> queue = new PriorityQueue<>((i1,i2)->{
if(i1[0]!=i2[0]){
return i1[0]-i2[0];
}else{
return i1[1]-i2[1];
}
});
int n = people.length;
int[][] res = new int[n][2];
//记录这个位置是否被访问过
boolean[] vis = new boolean[n];
for(int i=0; i<n; i++){
queue.offer(people[i]);
}
while(!queue.isEmpty()){
int[] top = queue.poll();
int count=0;
int i=0;
while(i<n && count<top[1]){
//这个位置没被访问过 或者 这个位置访问过了,但是h相等
if(!vis[i] || res[i][0]==top[0]){
count++;
}
i++;
}
while(vis[i]){
i++;
}
res[i] = top;
vis[i] = true;
}
return res;
}
}