题目·:给定两个大小分别为 m
和 n
的正序(从小到大)数组 nums1
和 nums2
。请你找出并返回这两个正序数组的 中位数 。
输入:nums1 = [1,3], nums2 = [2] 输出:2.00000 解释:合并数组 = [1,2,3] ,中位数 2
解析:第一种方法,先将两个数组合并为一个升序数组,然后找中位数。时间复杂度:O(m+n)
代码:
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
//第一种方法:先将两个数组合并,然后排序,找到中位数。
//创建arraylist,存储数组数据
ArrayList<Integer> list = new ArrayList<>();
//添加第一个数组
for (int i = 0; i < nums1.length; i++) {
list.add(nums1[i]);
}
//添加第二个数组
for (int i = 0; i < nums2.length; i++) {
list.add(nums2[i]);
}
//排序
Collections.sort(list);
//转化为数组
Integer[] num = list.toArray(new Integer[(list.size())]);
//寻找中位数
if (num.length %2 == 0){
return (num[num.length/2]+num[num.length/2-1])/2.0;
}else {
return num[num.length/2];
}
}
}
这种将两个数组通过list结合起来,引入了新的空间,执行用时和内存消耗都比较大。
第二种合并方法是通过一个新的数组进行合并,一定程度上缩小了执行时间。
int m = nums1.length;
int n = nums2.length;
//双指针解法,从后往前依次遍历
//新数组的长度为k+1,此时的k是最后一个元素的下标
int k = m+n-1;
int[] c =new int[k+1];
int i = m-1;
int j = n-1;
//当AB两个都有元素时
while (i>=0 && j >=0){
if (nums1[i] >= nums2[j]){
c[k--] = nums1[i--];
}else
c[k--] = nums2[j--];
}
if (i < 0){
while (j>=0)
c[k--] = nums2[j--];
}
if (j<0){
while (i >=0)
c[k--] = nums1[i--];
}
if (c.length %2 == 0){
return (c[c.length/2]+c[c.length/2-1])/2.0;
}else {
return c[c.length/2];
}
深入思考:
前面都是使用了合并数组的方式,时间复杂度为O(m+n),而我们并未利用到这两个有序数组的有序这个前提,寻找中位数,正是寻找第(m+n)/2小元素(数组长度为奇数),第(m+n)/2,(m+n)/2-1小元素,然后相加除2(数组长度为偶数时)。因此,可以用二分查找,找到第k小元素。
详细的描述可以参考leetcode原作者的解释,这里不做详细介绍(解法三)力扣https://leetcode.cn/problems/median-of-two-sorted-arrays/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-2/代码:
引申:寻找第K小元素