问题

给定两个大小分别为m和n的正序(从小到大)数组nums1和nums2。请你找出并返回这两个正序数组的中位数。

示例 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

方法1

  • 正常排序数组的中位数计算
    • 数组长度len%2==0,返回中间两个数的平均数
    • 数组长度len%2!=0,返回中间的数
  • 特殊情况,两个数组的其中一个为空,直接调用double findMedianSortedArrays(vector<int> &nums)
  • (直接思路)两个数组已经有序,可以选择直接合并,合并完成后计算中位数

时间复杂度:LeetCode-4.寻找两个正序数组的中位数 - 图1,空间复杂度:LeetCode-4.寻找两个正序数组的中位数 - 图2

  1. class Solution {
  2. public:
  3. double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
  4. int len1=nums1.size();
  5. int len2=nums2.size();
  6. if(len1==0){
  7. return findMedianSortedArrays(nums2);
  8. }else if(len2==0){
  9. return findMedianSortedArrays(nums1);
  10. }else{
  11. vector<int> nums;
  12. int i=0,j=0;
  13. while(i<len1&&j<len2){
  14. if(nums1[i]<nums2[j]){
  15. nums.push_back(nums1[i]);
  16. i++;
  17. }else{
  18. nums.push_back(nums2[j]);
  19. j++;
  20. }
  21. }
  22. while(i<len1){
  23. nums.push_back(nums1[i]);
  24. i++;
  25. }
  26. while(j<len2){
  27. nums.push_back(nums2[j]);
  28. j++;
  29. }
  30. return findMedianSortedArrays(nums);
  31. }
  32. }
  33. double findMedianSortedArrays(vector<int> &nums){
  34. int len=nums.size();
  35. if(len%2==0){
  36. return (nums[len/2-1]+nums[len/2])*1.0/2;
  37. }else{
  38. return nums[len/2]*1.0;
  39. }
  40. }
  41. };

方法2

Note: 排序数组问题在限定时间复杂度LeetCode-4.寻找两个正序数组的中位数 - 图3的情况下, 一般都可以使用二分法解决.
假设两个有序数组分别是LeetCode-4.寻找两个正序数组的中位数 - 图4LeetCode-4.寻找两个正序数组的中位数 - 图5。要找到第LeetCode-4.寻找两个正序数组的中位数 - 图6个元素,我们可以比较LeetCode-4.寻找两个正序数组的中位数 - 图7LeetCode-4.寻找两个正序数组的中位数 - 图8。由于LeetCode-4.寻找两个正序数组的中位数 - 图9LeetCode-4.寻找两个正序数组的中位数 - 图10的前面分别有LeetCode-4.寻找两个正序数组的中位数 - 图11LeetCode-4.寻找两个正序数组的中位数 - 图12,即LeetCode-4.寻找两个正序数组的中位数 - 图13个元素,对于LeetCode-4.寻找两个正序数组的中位数 - 图14LeetCode-4.寻找两个正序数组的中位数 - 图15中的较小值,最多只会有LeetCode-4.寻找两个正序数组的中位数 - 图16个元素比它小,那么它就不能是第LeetCode-4.寻找两个正序数组的中位数 - 图17小的数了。
因此可以归纳出三种情况:

  • 如果LeetCode-4.寻找两个正序数组的中位数 - 图18,则比LeetCode-4.寻找两个正序数组的中位数 - 图19小的数最多只有LeetCode-4.寻找两个正序数组的中位数 - 图20的前LeetCode-4.寻找两个正序数组的中位数 - 图21个数和LeetCode-4.寻找两个正序数组的中位数 - 图22的前LeetCode-4.寻找两个正序数组的中位数 - 图23个数,即比LeetCode-4.寻找两个正序数组的中位数 - 图24小的数最多只有LeetCode-4.寻找两个正序数组的中位数 - 图25个,因此LeetCode-4.寻找两个正序数组的中位数 - 图26不可能是第LeetCode-4.寻找两个正序数组的中位数 - 图27个数,LeetCode-4.寻找两个正序数组的中位数 - 图28LeetCode-4.寻找两个正序数组的中位数 - 图29也都不可能是第LeetCode-4.寻找两个正序数组的中位数 - 图30个数,可以全部排除。
  • 如果LeetCode-4.寻找两个正序数组的中位数 - 图31,则可以排除LeetCode-4.寻找两个正序数组的中位数 - 图32LeetCode-4.寻找两个正序数组的中位数 - 图33
  • 如果LeetCode-4.寻找两个正序数组的中位数 - 图34,则可以归入第一种情况处理。

    1. class Solution {
    2. public:
    3. int getKthElement(const vector<int>& nums1, const vector<int>& nums2, int k) {
    4. int m = nums1.size();
    5. int n = nums2.size();
    6. int index1 = 0, index2 = 0;
    7. while (true) {
    8. // 边界情况
    9. if (index1 == m) {
    10. return nums2[index2 + k - 1];
    11. }
    12. if (index2 == n) {
    13. return nums1[index1 + k - 1];
    14. }
    15. if (k == 1) {
    16. return min(nums1[index1], nums2[index2]);
    17. }
    18. // 正常情况
    19. int newIndex1 = min(index1 + k / 2 - 1, m - 1);
    20. int newIndex2 = min(index2 + k / 2 - 1, n - 1);
    21. int pivot1 = nums1[newIndex1];
    22. int pivot2 = nums2[newIndex2];
    23. if (pivot1 <= pivot2) {
    24. k -= newIndex1 - index1 + 1;
    25. index1 = newIndex1 + 1;
    26. }
    27. else {
    28. k -= newIndex2 - index2 + 1;
    29. index2 = newIndex2 + 1;
    30. }
    31. }
    32. }
    33. double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    34. int totalLength = nums1.size() + nums2.size();
    35. if (totalLength % 2 == 1) {
    36. return getKthElement(nums1, nums2, (totalLength + 1) / 2);
    37. }
    38. else {
    39. return (getKthElement(nums1, nums2, totalLength / 2) + getKthElement(nums1, nums2, totalLength / 2 + 1)) / 2.0;
    40. }
    41. }
    42. };