双数组中位数高效解法

给定两个已排序的数组 nums1 和 nums2,要求找到这两个数组合并后的中位数。中位数是位于合并后数组中间位置的数(如果数组长度为奇数)或中间两个数的平均值(如果数组长度为偶数)。要求算法的时间复杂度为 O(log(m + n)),其中 m 和 n 分别是 nums1 和 nums2 的长度。

算法思路

为了满足 O(log(m + n)) 的时间复杂度要求,不能直接合并两个数组再找中位数。可以采用二分查找的思想,将问题转化为在两个数组中寻找第 k 小的数(k 为中位数的位置)。

具体步骤如下:

  1. 中位数位置
    • 如果合并后的数组长度为奇数,中位数是第 (m + n + 1) / 2 小的数。
    • 如果为偶数,中位数是第 (m + n) / 2 和 (m + n) / 2 + 1 小的数的平均值。
  2. 二分查找
    • 每次比较 nums1 和 nums2 的第 k/2 个元素,较小的那个数组的前 k/2 个元素不可能包含第 k 小的数,因此可以排除这些元素。
    • 递归或迭代地缩小搜索范围,直到找到第 k 小的数。

Java实现

public class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length;
        int n = nums2.length;
        int total = m + n;
        if (total % 2 == 1) {
            return findKth(nums1, 0, m - 1, nums2, 0, n - 1, total / 2 + 1);
        } else {
            double left = findKth(nums1, 0, m - 1, nums2, 0, n - 1, total / 2);
            double right = findKth(nums1, 0, m - 1, nums2, 0, n - 1, total / 2 + 1);
            return (left + right) / 2.0;
        }
    }

    private int findKth(int[] nums1, int start1, int end1, int[] nums2, int start2, int end2, int k) {
        int len1 = end1 - start1 + 1;
        int len2 = end2 - start2 + 1;
        if (len1 > len2) {
            return findKth(nums2, start2, end2, nums1, start1, end1, k);
        }
        if (len1 == 0) {
            return nums2[start2 + k - 1];
        }
        if (k == 1) {
            return Math.min(nums1[start1], nums2[start2]);
        }
        int i = Math.min(len1, k / 2);
        int j = Math.min(len2, k / 2);
        if (nums1[start1 + i - 1] < nums2[start2 + j - 1]) {
            return findKth(nums1, start1 + i, end1, nums2, start2, end2, k - i);
        } else {
            return findKth(nums1, start1, end1, nums2, start2 + j, end2, k - j);
        }
    }
}

代码解释

  1. findMedianSortedArrays
    • 计算合并后的数组长度 total
    • 如果 total 为奇数,直接返回第 (total / 2 + 1) 小的数。
    • 如果为偶数,返回第 total / 2 和 total / 2 + 1 小的数的平均值。
  2. findKth
    • 确保 nums1 的长度不大于 nums2,简化逻辑。
    • 如果 nums1 为空,直接返回 nums2 的第 k 小元素。
    • 如果 k = 1,返回 nums1 和 nums2 的第一个元素中的较小值。
    • 比较 nums1 和 nums2 的第 k/2 个元素,排除较小元素的前 k/2 部分,递归查找剩余部分。

复杂度分析

  • 时间复杂度:O(log(m + n)),每次递归将问题规模减半。
  • 空间复杂度:O(log(m + n)),递归栈的深度。

简单总结

通过二分查找的思想,每次排除不可能包含中位数的部分,将时间复杂度优化到 O(log(m + n))。算法的核心是递归地在两个数组中查找第 k 小的数,逐步缩小搜索范围。

双数组中位数高效解法_第1张图片

你可能感兴趣的:(力扣刷题,算法,leetcode)