LeetCode 0004 -- 寻找两个有序数组的中位数

探讨了在两个有序数组中查找中位数的问题,提出了一种基于递归的算法,该算法的时间复杂度为O(log(m+n)),并详细解释了如何通过比较两个数组的中间元素来缩小搜索范围。

寻找两个有序数组的中位数

题目描述

给定两个大小为mn的有序数组nums1nums2

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

你可以假设nums1nums2不会同时为空。

示例1:

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

则中位数是 2.0

示例2:

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

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

解题思路

个人AC

无。

最优解

两个有序数组求中位数,问题可以一般化为:求两个有序数组的第k个数,当k = (m + n) / 2时为原问题的解。

怎么求第k个数?分别求出第一个和第二个数组的第k/2个数ab,然后比较ab

  • a < b,说明第k个数位于a的后半段或者b的前半段;
  • 否则a >= b,则第k个数位于a的前半段或者b的后半段;

问题规模缩小了一半,递归处理即可。时间复杂度为O(log(m + n))

public class Solution {
    
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        if (null == nums1 || null == nums2) throw new IllegalArgumentException("Input array can't be null");
        
        int n1 = nums1.length, n2 = nums2.length;
        // 处理任何一个nums为空的情况
        // 当其中一个nums为空的时候,需要针对另一个nums的奇偶性求中位数
        if (n1 == 0) {
            if ((n2 & 1) == 1) return 1.0 * nums2[n2 / 2];
            return (nums2[n2 / 2 - 1] + nums2[n2 / 2]) / 2.0;
        }
        if (n2 == 0) {
            if ((n1 & 1) == 1) return 1.0 * nums1[n1 / 2];
            return (nums1[n1 / 2 - 1] + nums1[n1 / 2]) / 2.0;
        }
        
        int n = n1 + n2; // 数组总长度
        if ((n & 1) == 1) { // 如果总长度为奇数,则找第(n / 2 + 1)个数
            return find_kth(nums1, 0, nums2, 0, n / 2 + 1);
        }
        // 总长度为偶数,找第(n / 2)和第(n / 2 + 1)个数
        return (find_kth(nums1, 0, nums2, 0, n / 2) + find_kth(nums1, 0, nums2, 0, n / 2 + 1)) / 2.0;
    }
    
    public int find_kth(int[] a, int a_begin, int[] b, int b_begin, int k) {
        // 当a_begin或b_begin超过数组长度,则第k个数为另一个数组第k个数
        if (a_begin >= a.length) return b[b_begin + k - 1];
        if (b_begin >= b.length) return a[a_begin + k - 1];
        // 当k为1时,两数组最小的那个为第一个数
        if (k == 1)
        	return Math.min(a[a_begin], b[b_begin]);
        
        int mid_a = Integer.MAX_VALUE, mid_b = Integer.MAX_VALUE;
        if (a_begin + k / 2 - 1 < a.length)
            mid_a = a[a_begin + k / 2 - 1];
        if (b_begin + k / 2 - 1 < b.length)
            mid_b = b[b_begin + k / 2 - 1];
        // 如果a数组的第(k / 2)个数小于b数组的第(k / 2)个数,
        // 表示总的第k个数位于a的第(k / 2)个数的后半段,或者是b的第(k / 2)个数的前半段
        // 由于范围缩小了(k / 2)个数,此时总的第k个数实际上等于新的范围内的第(k - k / 2)个数,依次递归
        if (mid_a < mid_b)
            return find_kth(a, a_begin + k / 2, b, b_begin, k - k / 2);
        //否则相反
        return find_kth(a, a_begin, b, b_begin + k / 2, k - k / 2);
    }
}

时间复杂度: O ( l o g ( m , n ) ) O(log(m, n)) O(log(m,n))

空间复杂度: O ( 1 ) O(1) O(1)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值