Leetcode 题解系列(三)

Median of Two Sorted Arrays

题目要求/There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

Example 1:
nums1 = [1, 3]
nums2 = [2]

The median is 2.0
Example 2:
nums1 = [1, 2]
nums2 = [3, 4]

The median is (2 + 3)/2 = 2.5
题目分析
1. 暴力解法

直接将两个数组一起排序,在求中位数。时间复杂度 O((m+n)log(m+n)) 或者 O((m+n)2)

2. 归并法

利用归并排序的思想,对两个数组进行归并。归并不用完全做完,只需完成一半即可求得中位数。时间复杂度 O((m+n)/2

3. 分割

思考:中位数既是将数组分为两半,那么只要找到一个点,可以将数组分为两个部分就好。
对于一个合乎条件的分割点,有:
+ 分割一个数组后,前一个数比另一个数组分割完后后面一个数大
+ 分割一个数组后,后一个数比另一个数组分割完后前面一个数
1. 采用朴素的移动法
每次检查分割是否符合条件,不是则向对应方向移动。代码如下

class Solution {
 public:
  double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    auto len1 = nums1.size(), len2 = nums2.size();
    if (len1 == 0) {
      return getMedian(nums2);
    }
    if (len2 == 0) {
      return getMedian(nums1);
    }
    auto half = (len1 + len2 + 1) / 2;
    auto sep1 = len1 / 2, sep2 = half - sep1;
    std::pair<long, long> p1, p2;
    for (;;) {
      p1 = separate(nums1, sep1), p2 = separate(nums2, sep2);
      if (p1.first <= p2.second && p2.first <= p1.second) {
        break;
      } else if (p1.first > p2.second) {
        sep1--;
        sep2++;
      } else {
        sep1++;
        sep2--;
      }
    }
    long mids[4] = {p1.first, p1.second, p2.first, p2.second};
    std::sort(mids, mids + 4);
    if ((len1 + len2) % 2 == 0) {
      return (static_cast<double>(mids[1]) + static_cast<double>(mids[2])) / 2;
    }
    return static_cast<double>(mids[1]);
  }
  std::pair<long, long> separate(std::vector<int>& nums, int pos) {
    long left = std::numeric_limits<long>::min(),
         right = std::numeric_limits<long>::max();
    if (pos > 0 && pos <= nums.size()) {
      left = nums[pos - 1];
    }
    if (pos >= 0 && pos < nums.size()) {
      right = nums[pos];
    }
    return std::make_pair(left, right);
  }
  double getMedian(std::vector<int> nums) {
    auto len = nums.size();
    if (len == 0) {
      return 0;
    } else if (len % 2 == 0) {
      return (static_cast<double>(nums[len / 2]) +
              static_cast<double>(nums[len / 2 - 1])) /
             2;
    }
    return static_cast<double>(nums[len / 2]);
  }
};

2. 使用二分的方法


class Solution2 {
 public:
  double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    auto len1 = nums1.size(), len2 = nums2.size();
    if (len1 > len2) {
      return findImpl(nums2, nums1);
    }
    return findImpl(nums1, nums2);
  }
  double findImpl(vector<int>& nums1, vector<int>& nums2) {
    auto len1 = nums1.size(), len2 = nums2.size();
    if (len1 == 0) {
      return getMedian(nums2);
    }
    long long half = (len1 + len2 + 1) / 2;
    long long up_bound = len1 + 1, low_bound = -1;
    long long sep1 = (up_bound + low_bound + 1) / 2, sep2 = half - sep1;
    std::pair<long, long> p1, p2;
    for (;;) {
      p1 = separate(nums1, sep1), p2 = separate(nums2, sep2);
      if (p1.first <= p2.second && p2.first <= p1.second) {
        break;
      } else if (p1.first > p2.second) {
        up_bound = sep1;
      } else {
        low_bound = sep1;
      }
      sep1 = (up_bound + low_bound + 1) / 2;
      sep2 = half - sep1;
    }
    long mids[4] = {p1.first, p1.second, p2.first, p2.second};
    std::sort(mids, mids + 4);
    if ((len1 + len2) % 2 == 0) {
      return (static_cast<double>(mids[1]) + static_cast<double>(mids[2])) / 2;
    }
    return static_cast<double>(mids[1]);
  }
  std::pair<long, long> separate(std::vector<int>& nums, long long pos) {
    long left = std::numeric_limits<long>::min(),
         right = std::numeric_limits<long>::max();
    if (pos > 0 && pos <= nums.size()) {
      left = nums[pos - 1];
    }
    if (pos >= 0 && pos < nums.size()) {
      right = nums[pos];
    }
    return std::make_pair(left, right);
  }
  double getMedian(std::vector<int> nums) {
    auto len = nums.size();
    if (len == 0) {
      return 0;
    } else if (len % 2 == 0) {
      return (static_cast<double>(nums[len / 2]) +
              static_cast<double>(nums[len / 2 - 1])) /
             2;
    }
    return static_cast<double>(nums[len / 2]);
  }
};

二分的方法理论上时间复杂度应该小于第一种,但是实际上leetcode的运行时间反而更慢了,可能是测试样例中,中位数均比较居中的缘故。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值