力扣4. 寻找两个正序数组的中位数

题目描述

给定两个大小为 mn 的正序(从小到大)数组 nums1nums2。请你找出这两个正序数组的中位数,并且要求算法的时间复杂度是 O ( l o g ( m + n ) ) O(log(m+n)) O(log(m+n))

示例

输入: nums1 = [1, 3], nums2 = [2]
输出: 2.0
解释: 合并数组后排序为 [1, 2, 3],中位数是 2。

输入: nums1 = [1, 2], nums2 = [3, 4]
输出: 2.5
解释: 合并数组后排序为 [1, 2, 3, 4],中位数是 (2 + 3) / 2 = 2.5。

解法一:合并排序

思路:

要求算法时间复杂度为 O ( l o g ( m + n ) ) O(log(m+n)) O(log(m+n)),不能使用简单的合并排序方法。可以使用归并排序的思想进行解决。

具体过程如下:

  1. 定义两个指针 p1p2,分别指向数组 nums1nums2 的起始位置。
  2. 判断两个指针所指向的元素大小,将小的元素加入到一个临时数组 temp 中,并将对应指针右移一位。
  3. 重复步骤 2,直到其中一个指针到达数组末尾。
  4. 判断剩余数组中的元素,并将剩余元素加入到 temp 数组中。
  5. 如果 temp 数组的长度为奇数,返回 temp 数组中的中间元素;如果为偶数,返回中间两个元素的平均值。

时间复杂度为 O ( m + n ) O(m+n) O(m+n),其中 mn 分别为 nums1nums2 的长度。合并两个数组的过程需要遍历全部元素。

代码:(合并排序,时间复杂度 O ( m + n ) O(m+n) O(m+n)

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length;
        int n = nums2.length;
        int[] temp = new int[m + n];

        int p1 = 0, p2 = 0, p = 0;
        while (p1 < m && p2 < n) {
            temp[p++] = nums1[p1] < nums2[p2] ? nums1[p1++] : nums2[p2++];
        }
        
        while (p1 < m) {
            temp[p++] = nums1[p1++];
        }
        
        while (p2 < n) {
            temp[p++] = nums2[p2++];
        }
        
        if ((m + n) % 2 == 0) {
            return (temp[(m + n) / 2 - 1] + temp[(m + n) / 2]) / 2.0;
        } else {
            return temp[(m + n) / 2] * 1.0;
        }
    }
}

解法二:二分查找

思路:

要求算法时间复杂度为 O ( l o g ( m + n ) ) O(log(m+n)) O(log(m+n)),可以考虑使用二分查找的思想进行解决。

对于两个有序数组的中位数而言,可以将其转化为寻找第 k 小的数的问题。具体过程如下:

  1. 定义两个指针 p1p2,分别指向数组 nums1nums2 的起始位置。
  2. 根据 k 的值,确定两个指针应该移动的步数。将 k 折半,然后分别比较 nums1[p1 + newP1 - 1]nums2[p2 + newP2 - 1] 的大小:
    • 如果 nums1[p1 + newP1 - 1] 小于 nums2[p2 + newP2 - 1],则在前 newP1 个元素中必然包含第 k 小的数。
    • 如果 nums1[p1 + newP1 - 1] 大于等于 nums2[p2 + newP2 - 1],则在前 newP2 个元素中必然包含第 k 小的数。
    • 如果 nums1[p1 + newP1 - 1] 等于 nums2[p2 + newP2 - 1],则 nums1[p1 + newP1 - 1]nums2[p2 + newP2 - 1] 即为第 k 小的数。
  3. 根据步数确定指针移动的方向,并将指针往前移动相应的步数。
  4. 重复步骤 2 和步骤 3,直到 k 缩小到 1
  5. 返回当前指针所指位置的元素,即为第 k 小的数。

时间复杂度为 O ( l o g ( m + n ) ) O(log(m+n)) O(log(m+n)),其中 mn 分别为 nums1nums2 的长度。每次查找过程中, k 的值都被折半,因此需要进行 l o g ( m + n ) log(m+n) log(m+n) 次。

代码:(二分查找,时间复杂度 O ( l o g ( m + n ) ) O(log(m+n)) O(log(m+n))

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length;
        int n = nums2.length;
        int total = m + n;

        if (total % 2 == 0) {
            int left = findKth(nums1, 0, nums2, 0, total / 2);
            int right = findKth(nums1, 0, nums2, 0, total / 2 + 1);
            return (left + right) / 2.0;
        } else {
            return findKth(nums1, 0, nums2, 0, total / 2 + 1);
        }
    }

    private int findKth(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 findKth(nums1, start1 + k / 2, nums2, start2, k - k / 2);
        } else {
            return findKth(nums1, start1, nums2, start2 + k / 2, k - k / 2);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值