0
点赞
收藏
分享

微信扫一扫

力扣经典 4. 寻找两个正序数组的中位数(多种语言解)

        给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。算法的时间复杂度应该为 O(log (m+n)) 。

目录

题目描述

知识点

解题思路

完整代码

Python

Java

C


题目描述

 

知识点

  1. 中位数的定义:一个集合的中位数将集合划分为两个等长的子集,其中一个子集的元素总是大于另一个子集的元素。
  2. 二分查找:由于数组是有序的,并且要求算法的时间复杂度为O(log(m+n)),我们需要使用二分查找技术来达到这个要求。
  3. 分治算法:通过将大问题分解为小问题来解决的一种算法策略。
  4. 数组操作:如索引访问、长度计算等基本操作。

解题思路

        要达到O(log(m+n))的时间复杂度,直接合并两个数组后找中位数的方法(时间复杂度为O(m+n))不可取。我们需要用到二分查找和分治的思想,关键是找到一个切分点,将两个数组分别切分为左右两部分,使得左边的元素总是小于右边的元素,并且左右两边的元素总数相等(或者只差一个元素,当总元素个数为奇数时)。

  1. 将较短的数组作为二分查找的对象,这样可以缩小查找范围,设较短的数组为A,较长的数组为B。
  2. 在A中设定一个切点i,在B中自动确定切点j,使得i+j等于两数组长度之和的一半(或一半多一,当总元素个数为奇数时)。
  3. 调整i的位置,使得A[i-1] <= B[j]B[j-1] <= A[i],此时左边的元素总是小于右边的元素。
  4. 根据左右两部分的长度关系确定中位数:如果总长度是奇数,中位数是左边最大的数;如果总长度是偶数,中位数是左边最大的数和右边最小的数的平均值。

完整代码

Python

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        A, B = nums1, nums2
        total = len(nums1) + len(nums2)
        half = total // 2
        
        if len(B) < len(A):
            A, B = B, A  # 保证A是较短的数组
        
        l, r = 0, len(A) - 1
        while True:
            i = (l + r) // 2  # A的切点
            j = half - i - 2  # B的切点
            
            Aleft = A[i] if i >= 0 else float("-infinity")
            Aright = A[i + 1] if (i + 1) < len(A) else float("infinity")
            Bleft = B[j] if j >= 0 else float("-infinity")
            Bright = B[j + 1] if (j + 1) < len(B) else float("infinity")
            
            # 分割正确
            if Aleft <= Bright and Bleft <= Aright:
                if total % 2:
                    return min(Aright, Bright)
                return (max(Aleft, Bleft) + min(Aright, Bright)) / 2
            elif Aleft > Bright:
                r = i - 1
            else:
                l = i + 1

Java

class Solution {
   public double findMedianSortedArrays(int[] nums1, int[] nums2) {
    if (nums1.length > nums2.length) {
        int[] temp = nums1; nums1 = nums2; nums2 = temp;  // 保证nums1是较短的数组
    }
    int m = nums1.length, n = nums2.length;
    int totalLeft = (m + n + 1) / 2;
    int l = 0, r = m;
    while (l < r) {
        int i = l + (r - l + 1) / 2;
        int j = totalLeft - i;
        if (nums1[i - 1] > nums2[j]) {
            r = i - 1;
        } else {
            l = i;
        }
    }
    int i = l, j = totalLeft - l;
    int nums1LeftMax = i == 0 ? Integer.MIN_VALUE : nums1[i - 1];
    int nums1RightMin = i == m ? Integer.MAX_VALUE : nums1[i];
    int nums2LeftMax = j == 0 ? Integer.MIN_VALUE : nums2[j - 1];
    int nums2RightMin = j == n ? Integer.MAX_VALUE : nums2[j];
    if (((m + n) % 2) == 1) {
        return Math.max(nums1LeftMax, nums2LeftMax);
    } else {
        return (Math.max(nums1LeftMax, nums2LeftMax) + Math.min(nums1RightMin, nums2RightMin)) / 2.0;
    }
}

}

C

double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size) {
    if (nums1Size > nums2Size) {  // 保证nums1是较短的数组
        int* temp = nums1; nums1 = nums2; nums2 = temp;
        int tmp = nums1Size; nums1Size = nums2Size; nums2Size = tmp;
    }
    int iMin = 0, iMax = nums1Size, halfLen = (nums1Size + nums2Size + 1) / 2;
    while (iMin <= iMax) {
        int i = (iMin + iMax) / 2;
        int j = halfLen - i;
        if (i < iMax && nums2[j-1] > nums1[i]){
            iMin = i + 1;  // i is too small
        } else if (i > iMin && nums1[i-1] > nums2[j]) {
            iMax = i - 1;  // i is too big
        } else {  // i is perfect
            int maxLeft = 0;
            if (i == 0) { maxLeft = nums2[j-1]; }
            else if (j == 0) { maxLeft = nums1[i-1]; }
            else { maxLeft = fmax(nums1[i-1], nums2[j-1]); }
            if ((nums1Size + nums2Size) % 2 == 1) { return maxLeft; }

            int minRight = 0;
            if (i == nums1Size) { minRight = nums2[j]; }
            else if (j == nums2Size) { minRight = nums1[i]; }
            else { minRight = fmin(nums2[j], nums1[i]); }

            return (maxLeft + minRight) / 2.0;
        }
    }
    return 0.0;
}

举报

相关推荐

0 条评论