LeetCode 04 寻找两个正序数组的中位数
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n)) 。
示例 1:
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000解释:合并数组 = [1,2,3] ,中位数 2
示例 2:
输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
提示:
- nums1.length == m
- nums2.length == n
- 0 <= m <= 1000
- 0 <= n <= 1000
- 1 <= m + n <= 2000
- -106 <= nums1[i], nums2[i] <= 106
大体思路
上来第一种解法当然是熟悉的暴力解法,将两个数组合到一起,然后sort一下,取中位数即可,显然我们知道这种方式并不可取。此时我们需要根据中位数的特性,即在整个数字列表的中间,那么其实我们只要构造出完整列表的前半部分就能取到中位数,再进一步实际上我们只关心最靠近中间的值是多少,对于前半部分的数值仅仅是我们用来获取靠近中间值的途径,所以并不需要保存下来,那么仅仅需要有变量用来保存最靠近中间的值即可,我们并不需要真正保存数组的前半部分。
第二个问题就是到底靠近中间的值指的是什么?对于奇数数量(假设长度为n)的列表,那么中间位置就是 (n + 1) / 2 - 1。而对于偶数数量的列表,中间位置就是 n/2 - 1 和 n/2 的中间。综上,我们仅仅需要遍历 (n+1) / 2 或者 n/2 + 1个数的值即可。比较两个数组里面的值,哪个值更小,就把哪个值塞到新的列表中,接着比较后面的值。
例子
例子1
[1,3] 和 [2], 因为完整数组的长度是3奇数,所以中间位置在 (3 + 1) / 2 - 1即索引1的位置,那么新数组的长度就必须是2(长度比索引大1),那么按次比较放入新的数组:
- nums1[0]为1和nums2[0]为2,1比较小放入新数组中,nums1往后一位,新数组为[1],数组长度为1,继续
- nums1[1]为3和nums2[0]为2,2比较小放入新数组中,nums2往后一位,新数组为[1,2],数组长度为2,停止
则中位数为2
这里实际我们并不需要实际上构造出新数组,用一个变量存一下结果值,新数组的长度就是两个数组的下标相加,那么简化一下就是:
- nums1[0]为1和nums2[0]为2,1比较小,结果值为1,nums1往后一位,数组下标和为1,继续
- nums1[1]为3和nums2[0]为2,2比较小,结果值为2,nums2往后一位,数组下标和为2,停止
例子2
[1,2] 和 [3,4],完整数组长度为4是偶数,所以中间位置在索引1和索引2之间,这样就需要用两个变量(用leftResult和rightResult,设置初始值为0)来存放结果,新数组的长度为3(即索引最大值 + 1)
- nums1[0]为1,nums2[0]为3,1比较小,那么rightResult为1,nums1往后一位,数组下标和为1,继续
- nums1[1]为2,nums2[0]为3,2比较小,那么rightResult为2,leftResult为原先rightResult的值1,nums1往后一位,数组下标和为2,继续
- (这里需要注意了,nums1数组已经被取完了,那么下面只能再取nums2内的值,所以我们简单起见直接将数组越界的值设置为无穷大,这样比较的时候就会直接去使用nums2内的值)nums1[2]为无穷大,nums2[0]为3,3比较小,那么rightResult为3,leftResult为原先rightResult的值2,nums2往后一位,数组下标和为3,结束
则中位数为 (2 + 3) / 2 为 2.5
代码
var findMedianSortedArrays = function(nums1, nums2) { |