LeetCode-day4-寻找两个正序数组的中位数(困难)

问题描述

  • 给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。
  • 请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
  • 你可以假设 nums1 和 nums2 不会同时为空。

示例

   nums1 = [1, 3]
   nums2 = [2]
   则中位数是 2.0

   nums1 = [1, 2]
   nums2 = [3, 4]
   则中位数是 (2 + 3)/2 = 2.5

题解

思路一

  • 分别获取两个数组的中位数比较大小
  • 将中位数大的数组的左侧和中位数小的数组的右侧重复获取中位数并比较直到传入的数组的长度为1
  • 返回剩余数组中的两个数的平均值
public static int lengthOfLongestSubstring(String s) {
  public double findMedianSortedArrays(int[] nums1, int[] nums2) {
      return findMedianSortedArrays(nums1, 0, nums1.length - 1,
              nums2, 0, nums2.length - 1);
  }

  public double findMedianSortedArrays(int[] nums1, Integer left1, Integer right1,
                                       int[] nums2, Integer left2, Integer right2) {
      double middle1 = getMiddle(nums1, left1, right1);
      double middle2 = getMiddle(nums2, left2, right2);
      int index1 = (right1 + left1) / 2;
      int index2 = (right2 + left2) / 2;
      if (right1.equals(left1) && right2.equals(left2)) {
          return (middle1 + middle2) / 2;
      }
      if (middle1 < middle2) {
          return findMedianSortedArrays(nums1, index1 + 1, right1, nums2, left2, index2  > 0 ? index2 - 1: index2);
      } else if (middle1 > middle2){
          return findMedianSortedArrays(nums1, left1, index1  > 0 ? index1 - 1: index1, nums2, index2 + 1, right2);
      } else {
          return middle1;
      }
  }
  // 获取中位数
  public static double getMiddle(int[] nums, int left, int right) {
      if (left == right) {
          return nums[left];
      } else {
          int index = (left + right) / 2;
          return (left - right + 1) % 2 == 0 ? (double) (nums[index] + nums[index + 1]) / 2 : nums[index];
      }
  }
}
  • 时间复杂度 O(log(max(m,n)))
  • 空间复杂度 O(1)

注:此方法采用leetcode上的示例验证是成功的,但是该思路是错误的,特此记录

思路二

  • 因为是求两个数组的中位数,所以只要找到两个数组中第(两个数组长度和的一半)小的数字即可找到
  • 此方法是leetcode大神的解决方案
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
    int n = nums1.length;
    int m = nums2.length;
    int left = (n + m + 1) / 2;
    int right = (n + m + 2) / 2;
    //将偶数和奇数的情况合并,如果是奇数,会求两次同样的 k 。
    return (getKth(nums1, 0, n - 1, nums2, 0, m - 1, left) + getKth(nums1, 0, n - 1, nums2, 0, m - 1, right)) * 0.5;  
}

private int getKth(int[] nums1, int start1, int end1, int[] nums2, int start2, int end2, int k) {
    int len1 = end1 - start1 + 1;
    int len2 = end2 - start2 + 1;
    //让 len1 的长度小于 len2,这样就能保证如果有数组空了,一定是 len1
    if (len1 > len2) return getKth(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 = start1 + Math.min(len1, k / 2) - 1;
    int j = start2 + Math.min(len2, k / 2) - 1;

    if (nums1[i] > nums2[j]) {
        return getKth(nums1, start1, end1, nums2, j + 1, end2, k - (j - start2 + 1));
    }
    else {
        return getKth(nums1, i + 1, end1, nums2, start2, end2, k - (i - start1 + 1));
    }
}
  • 时间复杂度 O(log(m+n))
  • 空间复杂度 O(1)

LeetCode题目地址

猜你喜欢

转载自www.cnblogs.com/lastpriest/p/12910458.html