题目:
给定两个大小为 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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays
分析:
上回说到,这里的合并数组其实不是一定需要求得的,可以直接用指针来指示出中位数的位置,选取两个指针r1,r2,这里有一种思路是直接找出中间位,但是对于偶数的情况,有两个中间位,所以这里是双指针,r1指向的是现在的数,r2指向的是r1的上一个取值。另外就是循环执行的次数问题,这里是 (m+n)/2,当m+n是奇数的时候,直接向下取整,当m+n是偶数的时候,就是(m+n)/2和(m+n)/2-1刚好对应了r1和r2。
举个例子,a有2个元素,b有一个元素,则中间位就是3/2=1,执行两次到达,即k<=target,如果a有2个元素,b有2个元素,中间位是4/2=2,执行三次到达,前一位r2就是执行了两次的,所以就是(r1 + r2)/ 2.0。
代码:
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
//i,j分别是nums1,nums2的指示游标
int i, j;
i = j = 0;
int sum = nums1.length + nums2.length;
//target就是目标游标值
int target = sum / 2;
//flag表征奇偶性
int flag = sum % 2;
//记录结果,由于可能是偶数(两个中间值),所以需要有一个跟随变量r2存储r1的上一次值
int r1,r2;
r1 = r2 = 0;
//遍历次数到达游标值target
for(int k = 0; k <= target; k ++){
//r2作为r1的跟随变量,记录上一次的值
r2 = r1;
//数组遍历查找,注意这里的&&和||都是短路处理的,防止数组越界
//j>=nums2.length要写在nums1[i]<nums2[j]的前面,当j = nums2.length,可以避免数组越界
if(i < nums1.length && (j >= nums2.length || nums1[i] < nums2[j])){
//先赋值后i自加
r1 = nums1[i ++];
}else{
r1 = nums2[j ++];
}
}
//根据奇偶性确定最后值
if(flag == 1){
return r1;
}else{
//注意这里要隐式强制类型转换成float
return (r1 + r2) / 2.0;
}
}
}
总结:
这里采用了双指针的方法,没有选择合并数组,所以将空间复杂度由O(m+n)降到了O(1),时间复杂度不变,还是O(m+n),注意一下,这里通过短路逻辑来避免数组越界。还有跟快的方法吗?比如,二分一下,有跳跃查找的思想来代替连续查找,是否会取得更好的效果呢?