leetcode之寻找两个有序数组的中位数c++解法

leetcode之寻找两个有序数组的中位数c++解法


给定两个大小为 m 和 n 的 有序数组 nums1 和 nums2。

请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))

你可以假设 nums1 和 nums2 不会同时为空。

示例 1:

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

则中位数是 2.0

示例 2:

nums1 = [1, 2]
nums2 = [3, 4]

则中位数是 (2 + 3)/2 = 2.5

解题思路:

在任意位置 i 将有m个元素的数组nums1划分成两部分:

           left_nums1            |           right_nums1
nums1[0],nums1[1],...,nums[i-1]  |  nums[i],nums1[i+1],...,nums[m-1]

同理,在任意位置 j 将有n个元素的数组nums2划分成两部分:

           left_nums2            |           right_nums2
nums1[0],nums1[1],...,nums[j-1]  |  nums[j],nums1[j+1],...,nums[n-1]

如果将left_nums1和left_nums2合并成left_part, right_nums1和 right_nums2合并成right_part后满足:

1. left_part.size() = right_part.size()
2. max(left_part) < min(right_part)

那么中位数即为:mid =(max(left_part) + min(right_part))/ 2

要确保满足这两个条件只需保证:

- i+j=m-i+n-j (或i+j=m-i+n-j+1)即 i = 0~m, j = (m+n+1)/2-i, (m<=n)
	m<=n 是为了确保 j 不是负数,因为当m<=n时, (m+n+1)/2>=m,那么j=m-i>=0, 
	如果m>n,可能会出现 j = (m+n+1)/2-i<0的情况,从而导致错误。
- nums1[i-1]<nums2[j]
- nums2[j-1]<nums1[i]

所以,我们只需要在[0, m]中找到满足以上条件的 i 即可。采用以下步骤进行二叉树搜索:
3. 设imin=0,imax=m,然后在[imin,imax]中进行搜索
4. 令i = (imin+imax)/2,则 j = (m+n+1)/2
5. 此时已经满足第一个条件:两边长度相等或者左边比右边多一个元素(i+j=m-i+n-j+1,即左边i+j个数,右边(i+j-1)个数),也因此,当m+n为奇数时,中位数在左边。接下来会遇到三种情况:

  • nums1[i-1]>nums2[j]:意味着 i 太大,要左移,搜索 i 的范围缩小到[imin,i-1]
  • nums2[j-1]>nums1[i]:意味着 i 太小,要右移, 搜索 i 的范围缩小到[i+1, imax]
  • nums1[i-1]<nums2[j] 且 nums2[j-1]<nums1[i]:意味着找到目标 i ,可以停止搜索

找到 目标 i 之后,中位数为:

max(nums1[i-1],nums2[j-1]),当m+n为奇数时
(max(nums1[i-1],nums2[j-1])+ min(nums1[i]+nums2[j]))/ 2,当m+n为偶数时

另外,还有几个临界值需要考虑:

  • i = 0: 此时不存在nums[ i-1],所以不需要判断nums1[i-1]<nums2[j]是否成立,只需要判断nums1[i]>nums2[j-1]是否成立,如果不成立,则意味着 i 太小,要右移, 搜索 i 的范围缩小到[i+1, imax],如果成立,意味着 i 是完美的,我们可以停止搜索
  • i = m: 此时不存在nums[i],所以不需要判断nums1[i]>nums2[j-1]是否成立,只需要判断nums1[i-1]<nums2[j]是否成立,如果不成立,则意味着 i 太大,要左移, 搜索 i 的范围缩小到[imin, i-1],如果成立,意味着 i 是完美的,我们可以停止搜索
  • j = 0:此时不存在nums2[j-1]
  • j = n:此时不存在nums2[j]

综上所述,在循环搜索中只会遇到以下3种情况:

  1. j>0且i<m且nums1[i]<nums2[j-1],这意味着 i 太小,我们必须增大它 (实际上,i<m⟹j>0始终成立,所以不需检查j>0是否成立)
  2. i>0且j<n且nums1[i-1]>nums2[j],这意味着 i 太大,我们必须减小它。( 实际上,i>0⟹j<n始终成立,所以不需要检查j<n是否成立 )
  3. 12都不满足,即(j=0或i=m或nums1[i]>nums2[j-1])或(i=0或j=n或nums1[i-1]<nums2[j]),意味着 i 是完美的,我们可以停止搜索
class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int m = nums1.size();
        int n = nums2.size();
        if(m>n){
            nums1.swap(nums2);
            int t = m; m = n; n= t;
        }
        int imin=0,imax=m,halflen=(m+n+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;
            else if(i>imin&&nums1[i-1]>nums2[j])
                imax = i-1;
            else{
                int maxLeft = 0;
                if(i==0)
                    maxLeft = nums2[j-1];
                else if(j==0)
                    maxLeft = nums1[i-1];
                else
                    maxLeft = max(nums2[j-1],nums1[i-1]);
                if((m+n)%2==1)  //当m+n为奇数时,中位数是左边的最大值
                    return maxLeft;
                
                int minRight = 0;
                if(i==m)
                    minRight = nums2[j];
                else if(j==n)
                    minRight = nums1[i];
                else
                    minRight = min(nums2[j],nums1[i]);
                
                return (maxLeft+minRight)/2.0; //除以2.0使得结果为浮点数,如果除以整型2,那么3/2结果将是1,从而导致错误
            }
        }
        return 0.0;
    }
};
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值