【递归】两个正序数组的中位数

61 阅读2分钟

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

算法的时间复杂度应该为 O(log (m+n)) 。

示例 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

findMedianSortedArrays 方法

  • 计算两个数组的总长度 len1len2
  • 计算中位数的位置 leftright
  • 根据总长度的奇偶性,调用 findKthNumber 方法找到第 leftright 小的数,并计算中位数。

findKthNumber 方法

  • 递归地找到两个有序数组合并后的第 k 小的数。
  • 处理边界情况:如果某个数组已经遍历完,则直接从另一个数组中取值。
  • 如果 k 为 1,返回两个数组当前起始位置的最小值。
  • 计算两个数组的中间值 mid1mid2,并根据中间值的大小递归调用 findKthNumber 方法。
public class Solution {

    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int len1 = nums1.length;
        int len2 = nums2.length;

        int left = (len1 + len2 + 1) / 2;
        int right = (len1 + len2 + 2) / 2;

        if ((len1 + len2) % 2 == 0) {
            return (findKthNumber(nums1, 0, nums2, 0, left) + findKthNumber(nums1, 0, nums2, 0, right)) / 2.0;
        } else {
            return findKthNumber(nums1, 0, nums2, 0, left);
        }
    }

    public int findKthNumber(int[] nums1, int start1, int[] nums2, int start2, int k) {
        if (start1 >= nums1.length) {
            return nums2[start2 + k - 1];
        }
        if (start2 >= nums2.length) {
            return nums1[start1 + k - 1];
        }
        if (k == 1) {
            return Math.min(nums1[start1], nums2[start2]);
        }
        int mid1 = start1 + k / 2 - 1 < nums1.length ? nums1[start1 + k / 2 - 1] : Integer.MAX_VALUE;
        int mid2 = start2 + k / 2 - 1 < nums2.length ? nums2[start2 + k / 2 - 1] : Integer.MAX_VALUE;
        if (mid1 < mid2) {
            return findKthNumber(nums1, start1 + k / 2, nums2, start2, k - k / 2);
        } else {
            return findKthNumber(nums1, start1, nums2, start2 + k / 2, k - k / 2);
        }
    }

}