方法二 堆
思路
由于本题被划分为堆问题,所以可以考虑使用堆来解决问题,毕竟堆也是可以用来排序的;
由于中位数要求所给数据是已排序的,所以可以将排序数据分为两部分,分别为左边部分left以及右边部分right,两者之间需要满足一下关系:
由于中位数求值需要left的最大值,以及right的最小值,所以对left使用最大堆存储,使用最小堆存储right;
而当满足情况(1)时,中位数medium就是left.max与right.min的平均值,而对于情况(2)则中位数medium为left.max;
那么我们来说说插入的操作吧,首先我们需要确定插入时left与right的情况:
1.当满足情况(1)时,当插入一个数据num时,数据总数变为奇数,也就是说中位数会变为left.max,此时数据应该插入left中,但是由于left存储的是已排序的左边数据,而num现在无法确定其属于哪一边,所以无法直接将num插入left中,但是我们知道right是一个最小堆,所以我们可以先将num插入right中,此时right堆顶元素是right中的最小值,将其移入left中即可。
2.当满足情况(2)时,插入一个数据num,数据总数会变为偶数,也就是说中位数变为,此时数据应该插入right中,同样由于不知道num究竟属于哪一边,所以需要先将num插入left,取出最大值max插入right中。
插入数据的时间复杂度:O(logn),每次添加数据时需要调整一次堆结构,时间复杂度为O(logn);
查询中位数的时间复杂度:O(1),中位数在插入数据时就已经计算好了,所以查询的时间为O(1);
空间复杂度为O(n),存储数据。
import java.util.*; public class Solution { /** * the medians * @param operations int整型二维数组 ops * @return double浮点型一维数组 */ public double[] flowmedian (int[][] operations) { // 存储中位数 List<Double> list = new ArrayList<>(); MedianHolder holder = new MedianHolder(); for (int i = 0; i < operations.length; i++) { if (operations[i][0] == 1) { holder.add(operations[i][1]); } if (operations[i][0] == 2) { list.add(holder.getMedian()); } } double[] medians = new double[list.size()]; for (int j = 0; j < list.size(); j++) { medians[j] = list.get(j); } return medians; } class MedianHolder { double medianNum = -1; // 建立最小堆存放排序后的右边的数据,堆顶是右边数据的最小值 PriorityQueue<Integer> rightMinHead = new PriorityQueue<>(); // 建立最大堆,存放排序后左边的数据,堆顶是左边数据的最大值 PriorityQueue<Integer> leftMaxHeap = new PriorityQueue<>(new Comparator<Integer>() { @Override public int compare (Integer o1, Integer o2) { return o2 - o1; } }); public void add (int num) { // 如果新增一个数,元素的总数量为变为偶数 if (leftMaxHeap.size() > rightMinHead.size()) { leftMaxHeap.offer(num); rightMinHead.offer(leftMaxHeap.poll()); // 更新中位数 medianNum = (leftMaxHeap.peek() + rightMinHead.peek()) / 2.0; return; } else { // 如果新增一个数,元素的总数量为变为奇数 rightMinHead.offer(num); leftMaxHeap.offer(rightMinHead.poll()); // 更新中位数 medianNum = leftMaxHeap.peek(); return; } } public double getMedian () { return this.medianNum; } } }