题解提到用可并堆维护这题的中位数,但对于这个做法的正确性,没有一篇做出了比较详细正确的解释。
绝大多数题解对于可并堆正确性的说明是:由于后一个区间的中位数小于前一个区间的中位数,而两个区间合并,中位数必然介于原来的两个中位数之间,所以中位数一定不会是已经被删除的数。然而这种说明是不完整的。
假设这里使用的是大根堆。前一个区间中被删除的是大于等于中位数的元素。由于新中位数小于等于前一个区间的中位数(并且前一步中,等于中位数的数至少有一个得到了保留),所以这一部分是正确的。
然而,对于后一个区间,被删除的同样是大于等于中位数的元素,按照上述说法,它们是完全可能成为新中位数的,这就站不住脚了。为了证明题解正确性,我们必须说明,这些元素同样都不可能成为新的中位数。
事实上,我们可以证明,后一个区间中被删除的元素,一定都大于等于前一个区间的中位数。又由于等于前一个区间中位数的数已经有一个被保留,所以算法是正确的。
如何证明呢?首先从新加入了一个单独的数,比它前一个区间的中位数更小这种场景开始。这时可以发现,考虑将原区间和新的数合并以后的集合排序,那么中位数顶多移动了一个位置。然而,在先前的加入操作中,没有触发前一个区间与再上一个区间的合并;而由于中位数一次只移动一位,所以被删除的数一定曾经作为中位数出现。于是可以得出,这些被删除的数一定大于等于上一个区间的中位数,也就不会在接下来合并中产生贡献。
而当发生连续合并时(也就是某个区间被合并,然后上一个区间也立刻被合并的场景),由于合并只加入了后一个区间的一半元素,所以顶多需要一次 pop 操作,同样只会让中位数移动一位,所以以上论证依然成立。
这样可以证明,在这道题中,合并堆的思路是正确的。
然而对于以下更广义的题目:
给定若干集合,总大小为 n,要求支持:
- 查询某集合中位数。
- 合并集合。
就不能采取合并堆的方式来完成,可以被以下数据卡掉:
初始集合 {1,4,5},{2,3},询问中合并两集合。