原题: 给定两有序数组,长度都是n,在总共n^2个两两之和中,找到最小的k个值。
题目不新鲜,出现了也有很多年了,不过在目前的面试中还有使用。较好的方法显然是用最小堆,时间复杂度降到 O(klgk)不过网上大略搜了一下,没有找到完整实现,甚至连关键点都没提到,我这里就算是个补充吧。
用最小堆,元素是 A[i] + B[j]. 每次弹出堆顶,然后插入新元素,维护最小堆。这里的关键在于每次插入哪些元素。大多数人说的都是,对于弹出A[i] + B[j], 应该插入A[i+1] + B[j], 以及A[i] + B[j+1]。我们来看看事实是什么。
已有A,B 两数组,假设从0开始升序排列。
如果当前最小堆弹出了A[1]+B[0], 那么接下来显然应该插入A[1] + B[1], 同时还有A[2] + B[0]. A[3]以上的组合不必考虑,因为A[2] + B[0]才刚刚插入。
如果当前弹出了A[1] + B[1], 那么插入A[1] + B[2]. 还有其他要插的么? 其实已经没还有了。由于A[2] + B[0]已在堆中还未弹出,所以A[3] 以上的组合全都不用入堆。
简单列个表格如下, 弹出项除(0,0)外全都是假设:
selected(i, j)