题目描述
一道算法题:求两个排序数组的第k小的数字
- 描述:给定两个升序排序数组a、b,要求求出其中第k大的数字
- 例子:
a = [1,2,3,4,5,6] b = [3,4,5,6,7,8,9] k = 5 得到结果为:4
思路
最直接的思路是归并排序后直接返回,但这样的时间空间复杂度都比较大,而且也比较没必要。
后来想到可以通过在两个数组中从头开始从左向右搜索,记录搜索个数,当搜索到第k个时即返回,这样的时间复杂度为O(n),空间复杂度为O(1)(n为元素总数)
参考其他人的文章发现可以通过折半删除的方法来做,这里给出一个解释的很清楚的题解视频。
思路描述如下:
- 选出两个数组的前 k/2 个元素,即a[start…k/2], b[start…k/2]
- 比较两个元素的大小,去掉小的那一部分。(这一步最关键)
即如果a[k/2] < b[k/2],则a[start…k/2]都不再需要。 - k -= k/2
- 重复第一步直到 k = 1 时返回
这个解法的困惑在于:
-
为什么去掉小的那一部分,最后可以得到第k个元素?又或者说,怎么知道去掉小的那一部分里没有所需要的第k个元素?
这里更准确的说法是,如何确定去掉的那一部分在第k个元素的左边呢?
-
接下来是一个简短的证明:
我们现在知道的条件有:a[k/2] < b[k/2](另一种情况a>b也是等价的)
如何由此确定a[start…k/2] 不包含我们的第k个元素呢?我们可以从另一种角度来看:
-
如果我们证明了比a[k/2]大的元素超过了 n - k + 1(n为元素总数),这里比a[k/2]的元素也包括了b[k/2]和b[k/2]右边的元素,则反过来比a[k/2]小的元素就小于k,也就说明a[start…k/2]不包含第k小的元素
-
顺着这个思路来看,我们可以通过算式来表达这个关系:
右边元素的个数为: n
-