给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
示例 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
示例 3:
输入:nums1 = [0,0], nums2 = [0,0] 输出:0.00000
示例 4:
输入:nums1 = [], nums2 = [1] 输出:1.00000
示例 5:
输入:nums1 = [2], nums2 = [] 输出:2.00000
提示:
nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106
进阶:
你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗?
两个有序数组找中位数,可以先把两个有序数组合并成一个有序数组,然后找出中位数即可。使用归并排序中合并数组的思路。编码实现如下:
public static float twoSortMid(int[] nums1,int[] nums2) {
int len = nums1.length+nums2.length;//两个数组的长度
int[] nums3 = new int[len];//合并后的数组
int i = 0;//数组nums1的下标
int j = 0;//数组nums2的下标
int k = 0;//数组nums3的下标
float tmp;//目标值
//遍历数组nums1和nums2,并比较元素的大小,依次放入数组nums3中
while (i
可以不合并两个数组,使用指针找出第k大的元素即可。编码实现如下所示:
public static float twoSortMid1(int[] nums1,int[] nums2) {
int len = nums1.length+nums2.length;
int mid = len/2;
float tmp1 = (float)0.0;//mid的前一位的值
float tmp2 = (float)0.0;//mid对应的值
float tmp;//目标值
int i = 0;//数组nums1的下标
int j = 0;//数组nums2的下标
int k = 0;
//遍历数组nums1和nums2,并比较元素的大小,依次放入数组nums3中
while (i
这道题如果时间复杂度没有限定在 O(log(m+n)) ,我们可以用 的算法解决,用两个指针分别指向两个数组,比较指针下的元素大小,一共移动次数为 (m+n + 1)/2
,便是中位数。
首先,我们理解什么中位数:指的是该数左右个数相等。
比如:odd : [1,| 2 |,3]
,2
就是这个数组的中位数,左右两边都只要 1 位;
even: [1,| 2, 3 |,4]
,2,3
就是这个数组的中位数,左右两边 1 位;
那么,现在我们有两个数组:
num1: [a1,a2,a3,...an]
nums2: [b1,b2,b3,...bn]
[nums1[:left1],nums2[:left2] | nums1[left1:], nums2[left2:]]
只要保证左右两边 个数 相同,中位数就在 |
这个边界旁边产生。
如何找边界值,我们可以用二分法,我们先确定 num1
取 m1
个数的左半边,那么 num2
取 m2 = (m+n+1)/2 - m1
的左半边,找到合适的 m1
,就用二分法找。
当 [ [a1],[b1,b2,b3] | [a2,..an],[b4,...bn] ]
我们只需要比较 b3
和 a2
的关系的大小,就可以知道这种分法是不是准确的!
例如:我们令:
nums1 = [-1,1,3,5,7,9]
nums2 =[2,4,6,8,10,12,14,16]
当 m1 = 4,m2 = 3
,它的中位数就是median = (num1[m1] + num2[m2])/2
对于代码中边界情况,大家需要自己琢磨。
public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
int n1 = nums1.length;
int n2 = nums2.length;
if (n1>n2)
return findMedianSortedArrays(nums2, nums1);
int k = (n1 + n2 + 1)/2;//中位数下标
int left = 0;
int right = n1;
while(left < right){
int m1 = left +(right - left)/2;//nums1的中位数
int m2 = k - m1;//nums2的中位数
if (nums1[m1] < nums2[m2-1])//向右找中位数
left = m1 + 1;
else
right = m1;//向左找中位数
}
int m1 = left;
int m2 = k - left;
int c1 = Math.max(m1 <= 0 ? Integer.MIN_VALUE : nums1[m1-1],
m2 <= 0 ? Integer.MIN_VALUE : nums2[m2-1]);
if ((n1 + n2) % 2 == 1)
return c1;
int c2 = Math.min( m1 >= n1 ? Integer.MAX_VALUE :nums1[m1],
m2 >= n2 ? Integer.MAX_VALUE : nums2[m2]);
return (c1 + c2) * 0.5;
}