[Leetcode]4. 寻找两个正序数组的中位数

题目描述

给定两个大小为 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
  • 示例 3:
输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000
  • 示例 4:
输入:nums1 = [], nums2 = [1]
输出:1.00000
  • 示例 5:
输入:nums1 = [2], nums2 = []
输出:2.00000

第一种解法

class Solution {

  public double findMedianSortedArrays(int[] nums1, int[] nums2) {
    int len1 = nums1.length;
    int len2 = nums2.length;
    int len3 = len1 + len2;
    int[] nums3 = new int[len3];
    int cur1 = 0;
    int cur2 = 0;
    int cur3 = 0;
    while (cur1 < len1 && cur2 < len2) {
      if (nums1[cur1] < nums2[cur2]) {
        nums3[cur3++] = nums1[cur1++];
      } else {
        nums3[cur3++] = nums2[cur2++];
      }
    }
    while (cur1 < len1) {
      nums3[cur3++] = nums1[cur1++];
    }
    while (cur2 < len2) {
      nums3[cur3++] = nums2[cur2++];
    }
    return (nums3[(len3 - 1) / 2] + nums3[len3 / 2]) / 2.0;
  }

  public static void main(String[] args) {
    int[] nums1 = {1};
    int[] nums2 = {2};
    System.out.println(new Solution().findMedianSortedArrays(nums1, nums2));
  }
}

将两个有序数组合并成一个有序数组,时间复杂度O(m+n),空间复杂度O(m+n)。

第二种解法

class Solution2 {

  public double findMedianSortedArrays(int[] nums1, int[] nums2) {
    int len3 = nums1.length + nums2.length;
    int k1 = findKthSmallest(nums1, nums2, (len3 - 1) / 2);
    int k2 = findKthSmallest(nums1, nums2, (len3) / 2);
    return (k1 + k2) / 2.0;
  }

  /**
   * 查找两个数组中第K小元素
   */
  private int findKthSmallest(int[] nums1, int[] nums2, int k) {
    int len1 = nums1.length;
    int len2 = nums2.length;
    int cur1 = 0;
    int cur2 = 0;
    int cur3 = 0;
    while (cur1 < len1 && cur2 < len2) {
      if (nums1[cur1] < nums2[cur2]) {
        if (cur3 == k) {
          return nums1[cur1];
        }
        cur1++;
        cur3++;
      } else {
        if (cur3 == k) {
          return nums2[cur2];
        }
        cur2++;
        cur3++;
      }
    }
    while (cur1 < len1) {
      if (cur3 == k) {
        return nums1[cur1];
      }
      cur1++;
      cur3++;
    }
    while (cur2 < len2) {
      if (cur3 == k) {
        return nums2[cur2];
      }
      cur2++;
      cur3++;
    }
    return -1;
  }

  public static void main(String[] args) {
    int[] nums1 = {1, 3};
    int[] nums2 = {2};
    System.out.println(new Solution2().findMedianSortedArrays(nums1, nums2));
  }
}

不合并数组,找到中位数所在位置,时间复杂度O(m+n),空间复杂度O(1)。

第三种解法

class Solution3 {

  public double findMedianSortedArrays(int[] nums1, int[] nums2) {
    int len3 = nums1.length + nums2.length;
    int k1 = findKthSmallest(nums1, 0, nums2, 0, (len3 + 1) / 2);
    int k2 = findKthSmallest(nums1, 0, nums2, 0, (len3 + 2) / 2);
    return (k1 + k2) / 2.0;
  }

  /**
   * 查找两个数组中第K小元素,K范围为[1,,len]
   */
  private int findKthSmallest(int[] nums1, int nums1Left, int[] nums2, int nums2Left, int k) {
    int len1 = nums1.length;
    int len2 = nums2.length;
    //第一个数组查找完,直接查找第二个数组
    if (nums1Left >= len1) {
      return nums2[nums2Left + k - 1];
    }
    //第二个数组查找完,直接查找第一个数组
    if (nums2Left >= len2) {
      return nums1[nums1Left + k - 1];
    }
    if (k == 1) {
      return Math.min(nums1[nums1Left], nums2[nums2Left]);
    }
    //中位数向下取整
    int middleVal1 =
        (nums1Left + k / 2 - 1 < len1) ? nums1[nums1Left + k / 2 - 1] : Integer.MAX_VALUE;
    int middleVal2 =
        (nums2Left + k / 2 - 1 < len2) ? nums2[nums2Left + k / 2 - 1] : Integer.MAX_VALUE;
    if (middleVal1 < middleVal2) {
      return findKthSmallest(nums1, nums1Left + k / 2, nums2, nums2Left, k - k / 2);
    } else {
      return findKthSmallest(nums1, nums1Left, nums2, nums2Left + k / 2, k - k / 2);
    }
  }

  public static void main(String[] args) {
    int[] nums1 = {1, 2};
    int[] nums2 = {3, 4};
    System.out.println(new Solution3().findMedianSortedArrays(nums1, nums2));
  }
}

使用二分查找,将问题转换成求两个数组中第K小元素的问题。时间复杂度O(log(m+n))。

posted @ 2021-01-18 19:55  strongmore  阅读(45)  评论(0编辑  收藏  举报