注意有个问题 return这两种写法有什么区别吗 用被注释的那种就会有测试用例通不过
class Solution {
public double[] medianSlidingWindow(int[] nums, int k) {
int n = nums.length;
double[] ans = new double[n-k+1];
DualHeap dh = new DualHeap(k);
for(int i = 0; i < k;i++){
dh.addElement(nums[i]);
}
int index = 0;
ans[index++] = dh.getMid();
for(int i = k; i < n;i++){
dh.removeElement(nums[i-k]);
dh.addElement(nums[i]);
ans[index++] = dh.getMid();
}
return ans;
}
class DualHeap{
//大根堆
private PriorityQueue<Integer> maxHeap;
//小根堆
private PriorityQueue<Integer> minHeap;
// 窗口大小
private int k;
//删除表 当窗口往后移动时 某些元素退出窗口 它们要被删除
//采用延迟删除策略 先在删除表中记录 只有当该元素出现在大根堆或小根堆堆顶的时候才删除
private Map<Integer,Integer> delete;
//大根堆实际大小 因为存在延迟删除
private int maxHeapSize;
//小根堆实际大小
private int minHeapSize;
public DualHeap(int k){
minHeap = new PriorityQueue<>(new Comparator<Integer>(){//小根堆
public int compare(Integer i1,Integer i2){
// return i1 - i2;
return i1.compareTo(i2);
}
});
maxHeap = new PriorityQueue<>(new Comparator<Integer>(){ //大根堆
public int compare(Integer i1,Integer i2){
//return i2 - i1;
return i2.compareTo(i1);
}
});
this.k = k;
this.delete = new HashMap<>();
this.maxHeapSize = 0;
this.minHeapSize = 0;
}
public double getMid(){
//返回中位数
return k % 2 == 0 ? ((double)minHeap.peek() + maxHeap.peek()) / 2 : maxHeap.peek();
}
//删除一个元素
//这样会有测试用例无法通过
// public void removeElement(int d){
//单纯删除 可能会导致移除该堆顶后堆顶的下一个数也是要延迟删除的
//在makeblance时 将延迟删除的数 误当作 中位数候选数 要永远保持堆顶绝对不能是延迟删除的数
// if(minHeap.size() != 0 && minHeap.peek() == d){//小根堆堆顶 直接删除该数
// minHeap.poll();
// minHeapSize -= 1;
// }
// else if(maxHeap.size() != 0 && maxHeap.peek() == d){//大根堆堆顶直接删除该数
// maxHeap.poll();
// maxHeapSize -= 1;
// }
// else{
// //无法直接删除 记录在删除表中 延迟删除
// delete.put(d,delete.getOrDefault(d,0)+1);
// if(d < maxHeap.peek())
// maxHeapSize -= 1;
// else{
// minHeapSize -= 1;
// }
// }
// makebalance();
// }
public void removeElement(int num) {
delete.put(num, delete.getOrDefault(num, 0) + 1);
if (num <= maxHeap.peek()) {
--maxHeapSize;
//单纯删除 可能会导致移除该堆顶后堆顶的下一个数也是要延迟删除的
//在makeblance时 将延迟删除的数 误当作 中位数候选数 要永远保持堆顶绝对不能是延迟删除的数
if (num == maxHeap.peek()) {
prune(maxHeap);
}
} else {
--minHeapSize;
if (num == minHeap.peek()) {
prune(minHeap);
}
}
makebalance();
}
// 添加一个元素
public void addElement(int d){
if(maxHeap.size() == 0 || d <= maxHeap.peek()){//小于等于大根堆堆顶 或者大根堆为空(优先放入大根堆)
// 存放在小根堆
maxHeap.offer(d);
maxHeapSize += 1;
}
else{//大于小根堆堆顶
minHeap.offer(d);
minHeapSize += 1;
}
makebalance();
}
public void prune(PriorityQueue<Integer> heap){
//堆顶出现了delete表中的值
while(heap.size()!=0 && delete.getOrDefault(heap.peek(),0) > 0){
int peek = heap.peek();
delete.put(peek,delete.getOrDefault(peek,0) -1);
if(delete.getOrDefault(peek,0) == 0){
delete.remove(peek);
}
heap.poll();
}
}
public void makebalance(){
//异常情况
//小根堆比大根堆数多一
if(minHeapSize > maxHeapSize){
maxHeap.offer(minHeap.poll());
maxHeapSize += 1;
minHeapSize -=1;
prune(minHeap);
}
//大根堆比小根堆数多二
else if(maxHeapSize > minHeapSize + 1){
minHeap.offer(maxHeap.poll());
maxHeapSize -= 1;
minHeapSize +=1;
prune(maxHeap);
}
}
}
}