LeetCode_4:寻找两个正序数组的中位数(Python + Java)

  • 题目描述:

给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。

请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。

你可以假设 nums1 和 nums2 不会同时为空。

 

示例:

(1)
nums1 = [1, 3]
nums2 = [2]

则中位数是 2.0

(2)
nums1 = [1, 2]
nums2 = [3, 4]

则中位数是 (2 + 3)/2 = 2.5

 

  • 解法一:最简单亦是最容易想到的方法。将两个数组整合为一个数组后排序,取出中位数(当数组长度为偶数时,数组的中位数为中间两个数的平均数。当数组长度为基数时,中位数为最中间的数。)。
#Python
class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length;
        int n = nums2.length;

        if(m != 0 && n != 0){
            int[] nums = new int[nums1.length+nums2.length];
            System.arraycopy(nums1, 0, nums, 0,nums1.length );
            System.arraycopy(nums2, 0, nums, nums1.length,nums2.length );
            Arrays.sort(nums);
            if(nums.length % 2 == 0){
                return (nums[nums.length/2] + nums[nums.length/2-1])/2.0;
            }else{
                return nums[nums.length/2];
            }
        }

        else if(m == 0){
            if(n % 2 == 0){
                return (nums2[n/2] + nums2[n/2-1]) / 2.0;
            }else{
                return nums2[n/2];
            }
        }

        else if(n == 0){
            if(m % 2 == 0){
                return (nums1[m/2] + nums1[m/2-1]) / 2.0;
            }else{
                return nums1[m/2];
            }
        }

        else return 0;
    }
}
        
//Java
//(1)使用函数来拼接数组,并排序
class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length;
        int n = nums2.length;
        if(m == 0){
            if(n % 2 == 0){
                return (nums2[n/2] + nums2[n/2-1]) / 2.0;
            }else{
                return nums2[n/2];
            }
        }

        if(n == 0){
            if(m % 2 == 0){
                return (nums1[m/2] + nums1[m/2-1]) / 2.0;
            }else{
                return nums1[m/2];
            }
        }

        if(m == 0 && n == 0) return 0;

        if(m != 0 && n != 0){
            int[] nums = new int[nums1.length+nums2.length];
            System.arraycopy(nums1, 0, nums, 0,nums1.length );
            System.arraycopy(nums2, 0, nums, nums1.length,nums2.length );
            Arrays.sort(nums);
            if(nums.length % 2 == 0){
                return (nums[nums.length/2] + nums[nums.length/2-1])/2.0;
            }else{
                return nums[nums.length/2];
            }
        }
        else return 0;
    }
}

//(2)采用技巧拼接数组和排序。参考力扣精选解答。
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
    int[] nums;
    int m = nums1.length;
    int n = nums2.length;
    nums = new int[m + n];
    if (m == 0) {
        if (n % 2 == 0) {
            return (nums2[n / 2 - 1] + nums2[n / 2]) / 2.0;
        } else {

            return nums2[n / 2];
        }
    }
    if (n == 0) {
        if (m % 2 == 0) {
            return (nums1[m / 2 - 1] + nums1[m / 2]) / 2.0;
        } else {
            return nums1[m / 2];
        }
    }

    int count = 0;
    int i = 0, j = 0;
    while (count != (m + n)) {
        if (i == m) {
            while (j != n) {
                nums[count++] = nums2[j++];
            }
            break;
        }
        if (j == n) {
            while (i != m) {
                nums[count++] = nums1[i++];
            }
            break;
        }

        if (nums1[i] < nums2[j]) {
            nums[count++] = nums1[i++];
        } else {
            nums[count++] = nums2[j++];
        }
    }

    if (count % 2 == 0) {
        return (nums[count / 2 - 1] + nums[count / 2]) / 2.0;
    } else {
        return nums[count / 2];
    }
}
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-2/

        

 

  • 解法二:不合并,直接在两个数组中从小到大取出第k(k为两个数组长度和的一半)大的数。当两个数字之和为偶数时,中位数为第k大和它前面那个数(也就是第k-1大的数)的和的平均数。当两个数组之和为奇数时,中位数就为第k大的数。
#Python
class Solution(object):
    def findMedianSortedArrays(self, nums1, nums2):
        right = left = aStart = bStart = 0

        for i in range(0, ( len(nums1)+len(nums2) ) / 2 + 1):
            left = right
            if ( aStart < len(nums1) ) and ( (bStart >= len(nums2) ) or (nums1[aStart] < nums2[bStart]) ):  #循环条件是难点
                right = nums1[aStart]
                aStart += 1
            else:
                right = nums2[bStart]
                bStart += 1

        if ( len(nums1) + len(nums2) ) % 2 == 0:
            return (right + left)  / 2.0
        else:
            return right
//Java
class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2){
        int right = 0, left =0;
        int aStart=0, bStart =0;
        for (int i = 0; i <= (nums1.length+nums2.length)/2; i++) {
            left = right;
            if(aStart < nums1.length && (bStart >= nums2.length || nums1[aStart] < nums2[bStart])){   //这种写法的难点就在于这个判别式的表达
                right = nums1[aStart++];
            }else{
                right = nums2[bStart++];
            }
        }
        
        if( (nums1.length + nums2.length) % 2 == 0 ) return (right + left) / 2.0;
        else return right;
    }
}

 

  • 解法三:二分法查找
//Java
class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int len1 = nums1.length;
        int len2 = nums2.length;
        int total = len1 + len2;
        int left = (total + 1) / 2;
        int right = (total + 2) / 2;
        return (findK(nums1, 0, nums2, 0, left) + findK(nums1, 0, nums2, 0, right)) / 2.0;

    }

    //找到两个数组中第k小的元素
    public int findK(int[] nums1, int i, int[] nums2, int j, int k) {
        if (i >= nums1.length)
            return nums2[j + k - 1];
        if (j >= nums2.length)
            return nums1[i + k - 1];
        if (k == 1) {
            return Math.min(nums1[i], nums2[j]);
        }
        //计算出每次要比较的两个数的值,来决定 "删除"" 哪边的元素
        int mid1 = (i + k / 2 - 1) < nums1.length ? nums1[i + k / 2 - 1] : Integer.MAX_VALUE;
        int mid2 = (j + k / 2 - 1) < nums2.length ? nums2[j + k / 2 - 1] : Integer.MAX_VALUE;
        //通过递归的方式,来模拟删除掉前K/2个元素
        if (mid1 < mid2) {
            return findK(nums1, i + k / 2, nums2, j, k - k / 2);
        }
        return findK(nums1, i, nums2, j + k / 2, k - k / 2);
    }
}
//参考链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/zhe-ban-shan-chu-xun-zhao-liang-ge-you-xu-shu-zu-d/

 

 

 

 

 

 

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:深蓝海洋 设计师:CSDN官方博客 返回首页

打赏作者

爱学习的杨子

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值